Boost C++ Libraries: Ticket #9528: reactor_op_queue::get_descriptors O(N^2) https://svn.boost.org/trac10/ticket/9528 <p> I have simple P2P node. For benchmarking, it tries to open many tcp connections (as well as some small I/O on established connections) in single thread via boost::asio::ip::tcp::socket::async_connect - ~1000 per second. On Windows 7 it fully loads one CPU core. Profiler showed that ~75% of time is spent at following cycle of win_fd_set_adapter::set: </p> <pre class="wiki">// http://www.boost.org/doc/libs/1_55_0/boost/asio/detail/win_fd_set_adapter.hpp for (u_int i = 0; i &lt; fd_set_-&gt;fd_count; ++i) if (fd_set_-&gt;fd_array[i] == descriptor) return true; </pre><p> In my case it never finds descriptor in fd_array. And if comment that cycle then next hot spot is <a class="missing wiki">NtDeviceIoControlFile</a> - which consumes ~88% of time. </p> <p> win_fd_set_adapter::set basically does linear search O(N), and if not find then it appends descriptor. At hotspot case it was called by reactor_op_queue::get_descriptors </p> <pre class="wiki">// http://www.boost.org/doc/libs/1_55_0/boost/asio/detail/reactor_op_queue.hpp typename operations_map::iterator i = operations_.begin(); while (i != operations_.end()) { Descriptor descriptor = i-&gt;first; ++i; if (!descriptors.set(descriptor)) { boost::system::error_code ec(error::fd_set_failure); cancel_operations(descriptor, ops, ec); } } </pre><p> It calls descriptors.set for every element which results in quadratic overall complexity. </p> <p> Moreover, caller of get_descriptors is select_reactor::run - it clears fd_set before call of reactor_op_queue::get_descriptors </p> <pre class="wiki">// http://www.boost.org/doc/libs/1_55_0/boost/asio/detail/impl/select_reactor.ipp for (int i = 0; i &lt; max_select_ops; ++i) fd_sets_[i].reset(); // &lt;------------------------------- RESET fd_sets_[read_op].set(interrupter_.read_descriptor()); socket_type max_fd = 0; bool have_work_to_do = !timer_queues_.all_empty(); for (int i = 0; i &lt; max_select_ops; ++i) { have_work_to_do = have_work_to_do || !op_queue_[i].empty(); op_queue_[i].get_descriptors(fd_sets_[i], ops); if (fd_sets_[i].max_descriptor() &gt; max_fd) max_fd = fd_sets_[i].max_descriptor(); } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9528 Trac 1.4.3 chris_kohlhoff Mon, 05 May 2014 06:43:49 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/9528#comment:1 https://svn.boost.org/trac10/ticket/9528#comment:1 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Fixed on 'develop' in <a class="ext-link" href="https://github.com/boostorg/asio/commit/c06aa74f08a46dda05493f61d2b85cb7818e6f96"><span class="icon">​</span>c06aa74f08a46dda05493f61d2b85cb7818e6f96</a>. </p> <p> Merged to 'master' in <a class="ext-link" href="https://github.com/boostorg/asio/commit/4e1e7d731fcc5c0104567856de476f7ce8806d72"><span class="icon">​</span>4e1e7d731fcc5c0104567856de476f7ce8806d72</a>. </p> Ticket