$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r74827 - trunk/libs/asio/test/latency
From: chris_at_[hidden]
Date: 2011-10-08 18:12:31
Author: chris_kohlhoff
Date: 2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
New Revision: 74827
URL: http://svn.boost.org/trac/boost/changeset/74827
Log:
Add latency test programs.
Added:
   trunk/libs/asio/test/latency/
   trunk/libs/asio/test/latency/Jamfile.v2   (contents, props changed)
   trunk/libs/asio/test/latency/allocator.hpp   (contents, props changed)
   trunk/libs/asio/test/latency/coroutine.hpp   (contents, props changed)
   trunk/libs/asio/test/latency/high_res_clock.hpp   (contents, props changed)
   trunk/libs/asio/test/latency/tcp_client.cpp   (contents, props changed)
   trunk/libs/asio/test/latency/tcp_server.cpp   (contents, props changed)
   trunk/libs/asio/test/latency/udp_client.cpp   (contents, props changed)
   trunk/libs/asio/test/latency/udp_server.cpp   (contents, props changed)
   trunk/libs/asio/test/latency/unyield.hpp   (contents, props changed)
   trunk/libs/asio/test/latency/yield.hpp   (contents, props changed)
Added: trunk/libs/asio/test/latency/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/Jamfile.v2	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#
+
+import os ;
+
+if [ os.name ] = SOLARIS
+{
+  lib socket ;
+  lib nsl ;
+}
+else if [ os.name ] = NT
+{
+  lib ws2_32 ;
+  lib mswsock ;
+}
+else if [ os.name ] = HPUX
+{
+  lib ipv6 ;
+}
+
+project
+  : requirements
+    <library>/boost/system//boost_system
+    <library>/boost/thread//boost_thread
+    <define>BOOST_ALL_NO_LIB=1
+    <threading>multi
+    <os>SOLARIS:<library>socket
+    <os>SOLARIS:<library>nsl
+    <os>NT:<define>_WIN32_WINNT=0x0501
+    <os>NT,<toolset>gcc:<library>ws2_32
+    <os>NT,<toolset>gcc:<library>mswsock
+    <os>NT,<toolset>gcc-cygwin:<define>__USE_W32_SOCKETS
+    <os>HPUX,<toolset>gcc:<define>_XOPEN_SOURCE_EXTENDED
+    <os>HPUX:<library>ipv6
+  ;
+
+exe tcp_server : tcp_server.cpp ;
+exe tcp_client : tcp_client.cpp ;
+exe udp_server : udp_server.cpp ;
+exe udp_client : udp_client.cpp ;
Added: trunk/libs/asio/test/latency/allocator.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/allocator.hpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,52 @@
+//
+// allocator.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef ALLOCATOR_HPP
+#define ALLOCATOR_HPP
+
+#include <boost/aligned_storage.hpp>
+
+// Represents a single connection from a client.
+class allocator
+{
+public:
+  allocator()
+    : in_use_(false)
+  {
+  }
+
+  void* allocate(std::size_t n)
+  {
+    if (in_use_ || n >= 1024)
+      return ::operator new(n);
+    in_use_ = true;
+    return static_cast<void*>(&space_);
+  }
+
+  void deallocate(void* p)
+  {
+    if (p != static_cast<void*>(&space_))
+      ::operator delete(p);
+    else
+      in_use_ = false;
+  }
+
+private:
+  allocator(const allocator&);
+  allocator& operator=(const allocator&);
+
+  // Whether the reusable memory space is currently in use.
+  bool in_use_;
+
+  // The reusable memory space made available by the allocator.
+  boost::aligned_storage<1024>::type space_;
+};
+
+#endif // ALLOCATOR_HPP
Added: trunk/libs/asio/test/latency/coroutine.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/coroutine.hpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,87 @@
+//
+// coroutine.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef COROUTINE_HPP
+#define COROUTINE_HPP
+
+class coroutine
+{
+public:
+  coroutine() : value_(0) {}
+  bool is_child() const { return value_ < 0; }
+  bool is_parent() const { return !is_child(); }
+  bool is_complete() const { return value_ == -1; }
+private:
+  friend class coroutine_ref;
+  int value_;
+};
+
+class coroutine_ref
+{
+public:
+  coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
+  coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
+  ~coroutine_ref() { if (!modified_) value_ = -1; }
+  operator int() const { return value_; }
+  int& operator=(int v) { modified_ = true; return value_ = v; }
+private:
+  void operator=(const coroutine_ref&);
+  int& value_;
+  bool modified_;
+};
+
+#define CORO_REENTER(c) \
+  switch (coroutine_ref _coro_value = c) \
+    case -1: if (_coro_value) \
+    { \
+      goto terminate_coroutine; \
+      terminate_coroutine: \
+      _coro_value = -1; \
+      goto bail_out_of_coroutine; \
+      bail_out_of_coroutine: \
+      break; \
+    } \
+    else case 0:
+
+#define CORO_YIELD_IMPL(n) \
+  for (_coro_value = (n);;) \
+    if (_coro_value == 0) \
+    { \
+      case (n): ; \
+      break; \
+    } \
+    else \
+      switch (_coro_value ? 0 : 1) \
+        for (;;) \
+          case -1: if (_coro_value) \
+            goto terminate_coroutine; \
+          else for (;;) \
+            case 1: if (_coro_value) \
+              goto bail_out_of_coroutine; \
+            else case 0:
+
+#define CORO_FORK_IMPL(n) \
+  for (_coro_value = -(n);; _coro_value = (n)) \
+    if (_coro_value == (n)) \
+    { \
+      case -(n): ; \
+      break; \
+    } \
+    else
+
+#if defined(_MSC_VER)
+# define CORO_YIELD CORO_YIELD_IMPL(__COUNTER__ + 1)
+# define CORO_FORK CORO_FORK_IMPL(__COUNTER__ + 1)
+#else // defined(_MSC_VER)
+# define CORO_YIELD CORO_YIELD_IMPL(__LINE__)
+# define CORO_FORK CORO_FORK_IMPL(__LINE__)
+#endif // defined(_MSC_VER)
+
+#endif // COROUTINE_HPP
Added: trunk/libs/asio/test/latency/high_res_clock.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/high_res_clock.hpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,53 @@
+//
+// high_res_clock.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef HIGH_RES_CLOCK_HPP
+#define HIGH_RES_CLOCK_HPP
+
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+inline boost::uint64_t high_res_clock()
+{
+  LARGE_INTEGER i;
+  QueryPerformanceCounter(&i);
+  return i.QuadPart;
+}
+
+#elif defined(__GNUC__) && defined(__x86_64__)
+
+inline boost::uint64_t high_res_clock()
+{
+  unsigned long low, high;
+  __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
+  return (((boost::uint64_t)high) << 32) | low;
+}
+
+#else
+
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+inline boost::uint64_t high_res_clock()
+{
+  boost::posix_time::ptime now =
+    boost::posix_time::microsec_clock::universal_time();
+
+  boost::posix_time::ptime epoch(
+      boost::gregorian::date(1970, 1, 1),
+      boost::posix_time::seconds(0));
+
+  return (now - epoch).total_microseconds();
+}
+
+#endif
+
+#endif // HIGH_RES_CLOCK_HPP
Added: trunk/libs/asio/test/latency/tcp_client.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/tcp_client.cpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,125 @@
+//
+// tcp_client.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/read.hpp>
+#include <boost/asio/write.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/shared_ptr.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include "high_res_clock.hpp"
+
+using boost::asio::ip::tcp;
+using boost::posix_time::ptime;
+using boost::posix_time::microsec_clock;
+
+const int num_samples = 100000;
+
+struct transfer_all
+{
+  typedef std::size_t result_type;
+  std::size_t operator()(const boost::system::error_code& ec, std::size_t)
+  {
+    return (ec && ec != boost::asio::error::would_block) ? 0 : ~0;
+  }
+};
+
+int main(int argc, char* argv[])
+{
+  if (argc != 6)
+  {
+    std::fprintf(stderr,
+        "Usage: tcp_client <ip> <port> "
+        "<nconns> <bufsize> {spin|block}\n");
+    return 1;
+  }
+
+  const char* ip = argv[1];
+  unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
+  int num_connections = std::atoi(argv[3]);
+  std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4]));
+  bool spin = (std::strcmp(argv[5], "spin") == 0);
+
+  boost::asio::io_service io_service;
+  std::vector<boost::shared_ptr<tcp::socket> > sockets;
+
+  for (int i = 0; i < num_connections; ++i)
+  {
+    boost::shared_ptr<tcp::socket> s(new tcp::socket(io_service));
+
+    tcp::endpoint target(boost::asio::ip::address::from_string(ip), port);
+    s->connect(target);
+
+    s->set_option(tcp::no_delay(true));
+
+    if (spin)
+    {
+      tcp::socket::non_blocking_io nbio(true);
+      s->io_control(nbio);
+    }
+
+    sockets.push_back(s);
+  }
+
+  std::vector<unsigned char> write_buf(buf_size);
+  std::vector<unsigned char> read_buf(buf_size);
+
+  ptime start = microsec_clock::universal_time();
+  boost::uint64_t start_hr = high_res_clock();
+
+  boost::uint64_t samples[num_samples];
+  for (int i = 0; i < num_samples; ++i)
+  {
+    tcp::socket& socket = *sockets[i % num_connections];
+
+    boost::uint64_t t = high_res_clock();
+
+    boost::system::error_code ec;
+    boost::asio::write(socket,
+        boost::asio::buffer(write_buf),
+        transfer_all(), ec);
+
+    boost::asio::read(socket,
+        boost::asio::buffer(read_buf),
+        transfer_all(), ec);
+
+    samples[i] = high_res_clock() - t;
+  }
+
+  ptime stop = microsec_clock::universal_time();
+  boost::uint64_t stop_hr = high_res_clock();
+  boost::uint64_t elapsed_usec = (stop - start).total_microseconds();
+  boost::uint64_t elapsed_hr = stop_hr - start_hr;
+  double scale = 1.0 * elapsed_usec / elapsed_hr;
+
+  std::sort(samples, samples + num_samples);
+  std::printf("  0.0%%\t%f\n", samples[0] * scale);
+  std::printf("  0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale);
+  std::printf("  1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale);
+  std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale);
+  std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale);
+  std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale);
+  std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale);
+  std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale);
+  std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale);
+  std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale);
+  std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale);
+  std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale);
+  std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale);
+  std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale);
+  std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale);
+
+  double total = 0.0;
+  for (int i = 0; i < num_samples; ++i) total += samples[i] * scale;
+  std::printf("  mean\t%f\n", total / num_samples);
+}
Added: trunk/libs/asio/test/latency/tcp_server.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/tcp_server.cpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,114 @@
+//
+// tcp_server.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/tcp.hpp>
+#include <boost/asio/read.hpp>
+#include <boost/asio/write.hpp>
+#include <boost/shared_ptr.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+
+using boost::asio::ip::tcp;
+
+#include "yield.hpp"
+
+class tcp_server : coroutine
+{
+public:
+  tcp_server(tcp::acceptor& acceptor, std::size_t buf_size) :
+    acceptor_(acceptor),
+    socket_(acceptor_.get_io_service()),
+    buffer_(buf_size)
+  {
+  }
+
+  void operator()(boost::system::error_code ec, std::size_t n = 0)
+  {
+    reenter (this) for (;;)
+    {
+      yield acceptor_.async_accept(socket_, ref(this));
+
+      while (!ec)
+      {
+        yield boost::asio::async_read(socket_,
+            boost::asio::buffer(buffer_), ref(this));
+
+        if (!ec)
+        {
+          for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i];
+
+          yield boost::asio::async_write(socket_,
+              boost::asio::buffer(buffer_), ref(this));
+        }
+      }
+
+      socket_.close();
+    }
+  }
+
+  struct ref
+  {
+    explicit ref(tcp_server* p)
+      : p_(p)
+    {
+    }
+
+    void operator()(boost::system::error_code ec, std::size_t n = 0)
+    {
+      (*p_)(ec, n);
+    }
+
+  private:
+    tcp_server* p_;
+  };
+
+private:
+  tcp::acceptor& acceptor_;
+  tcp::socket socket_;
+  std::vector<unsigned char> buffer_;
+  tcp::endpoint sender_;
+};
+
+#include "unyield.hpp"
+
+int main(int argc, char* argv[])
+{
+  if (argc != 5)
+  {
+    std::fprintf(stderr,
+        "Usage: tcp_server <port> <nconns> "
+        "<bufsize> {spin|block}\n");
+    return 1;
+  }
+
+  unsigned short port = static_cast<unsigned short>(std::atoi(argv[1]));
+  int max_connections = std::atoi(argv[2]);
+  std::size_t buf_size = std::atoi(argv[3]);
+  bool spin = (std::strcmp(argv[4], "spin") == 0);
+
+  boost::asio::io_service io_service(1);
+  tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port));
+  std::vector<boost::shared_ptr<tcp_server> > servers;
+
+  for (int i = 0; i < max_connections; ++i)
+  {
+    boost::shared_ptr<tcp_server> s(new tcp_server(acceptor, buf_size));
+    servers.push_back(s);
+    (*s)(boost::system::error_code());
+  }
+
+  if (spin)
+    for (;;) io_service.poll();
+  else
+    io_service.run();
+}
Added: trunk/libs/asio/test/latency/udp_client.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/udp_client.cpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,105 @@
+//
+// udp_client.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/asio/ip/udp.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include "high_res_clock.hpp"
+
+using boost::asio::ip::udp;
+using boost::posix_time::ptime;
+using boost::posix_time::microsec_clock;
+
+const int num_samples = 100000;
+
+int main(int argc, char* argv[])
+{
+  if (argc != 6)
+  {
+    std::fprintf(stderr,
+        "Usage: udp_client <ip> <port1> "
+        "<nports> <bufsize> {spin|block}\n");
+    return 1;
+  }
+
+  const char* ip = argv[1];
+  unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[2]));
+  unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[3]));
+  std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4]));
+  bool spin = (std::strcmp(argv[5], "spin") == 0);
+
+  boost::asio::io_service io_service;
+
+  udp::socket socket(io_service, udp::endpoint(udp::v4(), 0));
+
+  if (spin)
+  {
+    udp::socket::non_blocking_io nbio(true);
+    socket.io_control(nbio);
+  }
+
+  udp::endpoint target(boost::asio::ip::address::from_string(ip), first_port);
+  unsigned short last_port = first_port + num_ports - 1;
+  std::vector<unsigned char> write_buf(buf_size);
+  std::vector<unsigned char> read_buf(buf_size);
+
+  ptime start = microsec_clock::universal_time();
+  boost::uint64_t start_hr = high_res_clock();
+
+  boost::uint64_t samples[num_samples];
+  for (int i = 0; i < num_samples; ++i)
+  {
+    boost::uint64_t t = high_res_clock();
+
+    boost::system::error_code ec;
+    socket.send_to(boost::asio::buffer(write_buf), target, 0, ec);
+    
+    do socket.receive(boost::asio::buffer(read_buf), 0, ec);
+    while (ec == boost::asio::error::would_block);
+
+    samples[i] = high_res_clock() - t;
+
+    if (target.port() == last_port)
+      target.port(first_port);
+    else
+      target.port(target.port() + 1);
+  }
+
+  ptime stop = microsec_clock::universal_time();
+  boost::uint64_t stop_hr = high_res_clock();
+  boost::uint64_t elapsed_usec = (stop - start).total_microseconds();
+  boost::uint64_t elapsed_hr = stop_hr - start_hr;
+  double scale = 1.0 * elapsed_usec / elapsed_hr;
+
+  std::sort(samples, samples + num_samples);
+  std::printf("  0.0%%\t%f\n", samples[0] * scale);
+  std::printf("  0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale);
+  std::printf("  1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale);
+  std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale);
+  std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale);
+  std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale);
+  std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale);
+  std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale);
+  std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale);
+  std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale);
+  std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale);
+  std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale);
+  std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale);
+  std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale);
+  std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale);
+
+  double total = 0.0;
+  for (int i = 0; i < num_samples; ++i) total += samples[i] * scale;
+  std::printf("  mean\t%f\n", total / num_samples);
+}
Added: trunk/libs/asio/test/latency/udp_server.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/udp_server.cpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,125 @@
+//
+// udp_server.cpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/ip/udp.hpp>
+#include <boost/shared_ptr.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <vector>
+#include "allocator.hpp"
+
+using boost::asio::ip::udp;
+
+#include "yield.hpp"
+
+class udp_server : coroutine
+{
+public:
+  udp_server(boost::asio::io_service& io_service,
+      unsigned short port, std::size_t buf_size) :
+    socket_(io_service, udp::endpoint(udp::v4(), port)),
+    buffer_(buf_size)
+  {
+  }
+
+  void operator()(boost::system::error_code ec, std::size_t n = 0)
+  {
+    reenter (this) for (;;)
+    {
+      yield socket_.async_receive_from(
+          boost::asio::buffer(buffer_),
+          sender_, ref(this));
+
+      if (!ec)
+      {
+        for (std::size_t i = 0; i < n; ++i) buffer_[i] = ~buffer_[i];
+        socket_.send_to(boost::asio::buffer(buffer_, n), sender_, 0, ec);
+      }
+    }
+  }
+
+  friend void* asio_handler_allocate(std::size_t n, udp_server* s)
+  {
+    return s->allocator_.allocate(n);
+  }
+
+  friend void asio_handler_deallocate(void* p, std::size_t, udp_server* s)
+  {
+    s->allocator_.deallocate(p);
+  }
+
+  struct ref
+  {
+    explicit ref(udp_server* p)
+      : p_(p)
+    {
+    }
+
+    void operator()(boost::system::error_code ec, std::size_t n = 0)
+    {
+      (*p_)(ec, n);
+    }
+
+  private:
+    udp_server* p_;
+
+    friend void* asio_handler_allocate(std::size_t n, ref* r)
+    {
+      return asio_handler_allocate(n, r->p_);
+    }
+
+    friend void asio_handler_deallocate(void* p, std::size_t n, ref* r)
+    {
+      asio_handler_deallocate(p, n, r->p_);
+    }
+  };
+
+private:
+  udp::socket socket_;
+  std::vector<unsigned char> buffer_;
+  udp::endpoint sender_;
+  allocator allocator_;
+};
+
+#include "unyield.hpp"
+
+int main(int argc, char* argv[])
+{
+  if (argc != 5)
+  {
+    std::fprintf(stderr,
+        "Usage: udp_server <port1> <nports> "
+        "<bufsize> {spin|block}\n");
+    return 1;
+  }
+
+  unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[1]));
+  unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[2]));
+  std::size_t buf_size = std::atoi(argv[3]);
+  bool spin = (std::strcmp(argv[4], "spin") == 0);
+
+  boost::asio::io_service io_service(1);
+  std::vector<boost::shared_ptr<udp_server> > servers;
+
+  for (unsigned short i = 0; i < num_ports; ++i)
+  {
+    unsigned short port = first_port + i;
+    boost::shared_ptr<udp_server> s(new udp_server(io_service, port, buf_size));
+    servers.push_back(s);
+    (*s)(boost::system::error_code());
+  }
+
+  if (spin)
+    for (;;) io_service.poll();
+  else
+    io_service.run();
+}
Added: trunk/libs/asio/test/latency/unyield.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/unyield.hpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,21 @@
+//
+// unyield.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifdef reenter
+# undef reenter
+#endif
+
+#ifdef yield
+# undef yield
+#endif
+
+#ifdef fork
+# undef fork
+#endif
Added: trunk/libs/asio/test/latency/yield.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/asio/test/latency/yield.hpp	2011-10-08 18:12:30 EDT (Sat, 08 Oct 2011)
@@ -0,0 +1,23 @@
+//
+// yield.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "coroutine.hpp"
+
+#ifndef reenter
+# define reenter(c) CORO_REENTER(c)
+#endif
+
+#ifndef yield
+# define yield CORO_YIELD
+#endif
+
+#ifndef fork
+# define fork CORO_FORK
+#endif