|
@@ -1,388 +0,0 @@
|
|
|
-// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
|
|
-//
|
|
|
-// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
-// purpose with or without fee is hereby granted, provided that the above
|
|
|
-// copyright notice and this permission notice appear in all copies.
|
|
|
-//
|
|
|
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
-// PERFORMANCE OF THIS SOFTWARE.
|
|
|
-
|
|
|
-// $Id$
|
|
|
-
|
|
|
-#include <config.h>
|
|
|
-
|
|
|
-#include <sys/types.h>
|
|
|
-#include <sys/socket.h>
|
|
|
-#include <sys/select.h>
|
|
|
-#include <sys/errno.h>
|
|
|
-
|
|
|
-#include <unistd.h>
|
|
|
-#include <stdint.h>
|
|
|
-#include <cstring>
|
|
|
-#include <netdb.h>
|
|
|
-
|
|
|
-#include <iostream>
|
|
|
-#include <vector>
|
|
|
-
|
|
|
-#include <boost/bind.hpp>
|
|
|
-#include <boost/asio.hpp>
|
|
|
-
|
|
|
-#include <exceptions/exceptions.h>
|
|
|
-
|
|
|
-#include <bench/benchmark.h>
|
|
|
-#include <bench/benchmark_util.h>
|
|
|
-
|
|
|
-using namespace std;
|
|
|
-using namespace isc;
|
|
|
-using namespace isc::bench;
|
|
|
-
|
|
|
-using namespace boost::asio;
|
|
|
-using ip::udp;
|
|
|
-namespace {
|
|
|
-class NativeSocketBenchMark {
|
|
|
-public:
|
|
|
- NativeSocketBenchMark(const int af, const char* const portstr,
|
|
|
- const size_t packet_size) :
|
|
|
- fd_(-1), packet_size_(packet_size), s_data_(packet_size),
|
|
|
- r_data_(packet_size)
|
|
|
- {
|
|
|
- struct addrinfo hints;
|
|
|
-
|
|
|
- memset(&hints, 0, sizeof(hints));
|
|
|
- hints.ai_family = af;
|
|
|
- hints.ai_socktype = SOCK_DGRAM;
|
|
|
- hints.ai_protocol = IPPROTO_UDP;
|
|
|
- int error = getaddrinfo(af == AF_INET6 ? "::1" : "127.0.0.1",
|
|
|
- portstr, &hints, &res_);
|
|
|
- if (error) {
|
|
|
- isc_throw(Exception, "getaddrinfo failed: " << gai_strerror(error));
|
|
|
- }
|
|
|
- // XXX: for brevity the following part is intentionally exception
|
|
|
- // unsafe.
|
|
|
- fd_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
|
|
|
- if (fd_ < 0) {
|
|
|
- isc_throw(Exception, "failed to open test socket: "
|
|
|
- << strerror(errno));
|
|
|
- }
|
|
|
- if (bind(fd_, res_->ai_addr, res_->ai_addrlen) != 0) {
|
|
|
- isc_throw(Exception, "failed to bind test socket: "
|
|
|
- << strerror(errno));
|
|
|
- }
|
|
|
- maxfd_ = fd_ + 1;
|
|
|
- FD_ZERO(&readfds_);
|
|
|
- FD_SET(fd_, &readfds_);
|
|
|
- }
|
|
|
- ~NativeSocketBenchMark() {
|
|
|
- if (fd_ >= 0) {
|
|
|
- close(fd_);
|
|
|
- }
|
|
|
- freeaddrinfo(res_);
|
|
|
- }
|
|
|
- void closeSocket() {
|
|
|
- if (fd_ >= 0) {
|
|
|
- close(fd_);
|
|
|
- }
|
|
|
- fd_ = -1;
|
|
|
- }
|
|
|
- unsigned int run() {
|
|
|
- const int cc_s = sendto(fd_, &s_data_[0], s_data_.size(), 0,
|
|
|
- res_->ai_addr, res_->ai_addrlen);
|
|
|
- if (cc_s != packet_size_) {
|
|
|
- isc_throw(Exception, "sendto failed, return value=" << cc_s);
|
|
|
- }
|
|
|
- fd_set readfds = readfds_;
|
|
|
- const int n = select(maxfd_, &readfds, NULL, NULL, NULL);
|
|
|
- if (n != 1 || !FD_ISSET(fd_, &readfds)) {
|
|
|
- isc_throw(Exception, "unexpected result from select, return value="
|
|
|
- << n);
|
|
|
- }
|
|
|
-
|
|
|
- struct sockaddr* from = reinterpret_cast<struct sockaddr*>(&ss_);
|
|
|
- socklen_t from_len = sizeof(ss_);
|
|
|
- r_data_.clear();
|
|
|
- const int cc_r = recvfrom(fd_, &r_data_[0], r_data_.capacity(), 0, from,
|
|
|
- &from_len);
|
|
|
- if (cc_r != packet_size_) {
|
|
|
- isc_throw(Exception, "recvfrom failed, return value=" << cc_r);
|
|
|
- }
|
|
|
-
|
|
|
- return (1);
|
|
|
- }
|
|
|
-private:
|
|
|
- int fd_;
|
|
|
- int maxfd_;
|
|
|
- const size_t packet_size_;
|
|
|
- struct addrinfo* res_;
|
|
|
- vector<uint8_t> s_data_;
|
|
|
- vector<uint8_t> r_data_;
|
|
|
- fd_set readfds_;
|
|
|
- struct sockaddr_storage ss_;
|
|
|
-};
|
|
|
-
|
|
|
-class ASIOBenchMark {
|
|
|
-public:
|
|
|
- ASIOBenchMark(io_service& io_service, const int af, const uint16_t portnum,
|
|
|
- const size_t packet_size) :
|
|
|
- packet_size_(packet_size),
|
|
|
- io_service_(io_service),
|
|
|
- socket_(io_service, af == AF_INET6 ? udp::v6() : udp::v4()),
|
|
|
- s_data_(packet_size), r_data_(packet_size),
|
|
|
- endpoint_(af == AF_INET6 ? udp::v6() : udp::v4(), portnum)
|
|
|
- {
|
|
|
- endpoint_.address(ip::address::from_string(
|
|
|
- af == AF_INET6 ? "::1" : "127.0.0.1"));
|
|
|
- socket_.bind(endpoint_);
|
|
|
- }
|
|
|
- unsigned int run() {
|
|
|
- isc_throw(Exception, "test is performed for a base class");
|
|
|
- }
|
|
|
- void cleanup() {
|
|
|
- socket_.close();
|
|
|
- io_service_.reset();
|
|
|
- }
|
|
|
-protected:
|
|
|
- const size_t packet_size_;
|
|
|
- io_service& io_service_;
|
|
|
- udp::socket socket_;
|
|
|
- vector<uint8_t> s_data_;
|
|
|
- vector<uint8_t> r_data_;
|
|
|
- udp::endpoint endpoint_;
|
|
|
- udp::endpoint sender_endpoint_;
|
|
|
- boost::system::error_code serror_;
|
|
|
-};
|
|
|
-
|
|
|
-class ASIOSyncBenchMark : public ASIOBenchMark {
|
|
|
-public:
|
|
|
- ASIOSyncBenchMark(io_service& io_service, const int af,
|
|
|
- const uint16_t portnum, const size_t packet_size) :
|
|
|
- ASIOBenchMark(io_service, af, portnum, packet_size),
|
|
|
- fd_(socket_.native()), maxfd_(fd_ + 1)
|
|
|
- {
|
|
|
- FD_ZERO(&readfds_);
|
|
|
- FD_SET(fd_, &readfds_);
|
|
|
- }
|
|
|
- unsigned int run() {
|
|
|
- const size_t cc_s = socket_.send_to(
|
|
|
- boost::asio::buffer(&s_data_[0], s_data_.size()),
|
|
|
- endpoint_, 0, serror_);
|
|
|
- if (cc_s != packet_size_ || serror_) {
|
|
|
- isc_throw(Exception, "asio::send_to failed, return value="
|
|
|
- << cc_s);
|
|
|
- }
|
|
|
-
|
|
|
- // add the overhead of select for fair comparison
|
|
|
- fd_set readfds = readfds_;
|
|
|
- const int n = select(maxfd_, &readfds, NULL, NULL, NULL);
|
|
|
- if (n != 1 || !FD_ISSET(fd_, &readfds)) {
|
|
|
- isc_throw(Exception, "unexpected result from select, return value="
|
|
|
- << n);
|
|
|
- }
|
|
|
-
|
|
|
- r_data_.clear();
|
|
|
- const size_t cc_r = socket_.receive_from(
|
|
|
- boost::asio::buffer(&r_data_[0], r_data_.capacity()),
|
|
|
- sender_endpoint_);
|
|
|
- if (cc_r != packet_size_) {
|
|
|
- isc_throw(Exception, "asio::receive_from failed, return value="
|
|
|
- << cc_r);
|
|
|
- }
|
|
|
-
|
|
|
- return (1);
|
|
|
- }
|
|
|
-private:
|
|
|
- const int fd_;
|
|
|
- const int maxfd_;
|
|
|
- fd_set readfds_;
|
|
|
-};
|
|
|
-
|
|
|
-class ASIOAsyncBenchMark : public ASIOBenchMark {
|
|
|
-public:
|
|
|
- ASIOAsyncBenchMark(io_service& io_service, const int af,
|
|
|
- const uint16_t portnum, const size_t packet_size,
|
|
|
- const unsigned int iteration, const bool async_send) :
|
|
|
- ASIOBenchMark(io_service, af, portnum, packet_size),
|
|
|
- iteration_(iteration), n_received_(0), async_send_(async_send)
|
|
|
- {}
|
|
|
- unsigned int run() {
|
|
|
- if (!async_send_) {
|
|
|
- startReceive();
|
|
|
- }
|
|
|
- sendTo();
|
|
|
- io_service_.run();
|
|
|
- return (iteration_);
|
|
|
- }
|
|
|
-private:
|
|
|
- void sendTo() {
|
|
|
- if (async_send_) {
|
|
|
- socket_.async_send_to(
|
|
|
- boost::asio::buffer(&s_data_[0], s_data_.size()),
|
|
|
- endpoint_,
|
|
|
- boost::bind(&ASIOAsyncBenchMark::sendCompleted, this,
|
|
|
- placeholders::error,
|
|
|
- placeholders::bytes_transferred));
|
|
|
- } else {
|
|
|
- const size_t cc_s = socket_.send_to(
|
|
|
- boost::asio::buffer(&s_data_[0], s_data_.size()),
|
|
|
- endpoint_, 0, serror_);
|
|
|
- if (cc_s != packet_size_ || serror_) {
|
|
|
- isc_throw(Exception, "asio::send_to failed, return value="
|
|
|
- << cc_s);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- void handleReceive(const boost::system::error_code& error,
|
|
|
- size_t bytes_recvd)
|
|
|
- {
|
|
|
- if (error || bytes_recvd != packet_size_) {
|
|
|
- isc_throw(Exception, "asio::asyncronous receive failed: "
|
|
|
- << error << ", #received=" << bytes_recvd);
|
|
|
- }
|
|
|
- if (++n_received_ == iteration_) {
|
|
|
- io_service_.stop();
|
|
|
- } else {
|
|
|
- sendTo();
|
|
|
- if (!async_send_) {
|
|
|
- startReceive();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- void startReceive() {
|
|
|
- socket_.async_receive_from(
|
|
|
- boost::asio::buffer(&r_data_[0], r_data_.capacity()),
|
|
|
- sender_endpoint_,
|
|
|
- boost::bind(&ASIOAsyncBenchMark::handleReceive, this,
|
|
|
- placeholders::error,
|
|
|
- placeholders::bytes_transferred));
|
|
|
- }
|
|
|
- void sendCompleted(const boost::system::error_code& error UNUSED_PARAM,
|
|
|
- size_t bytes_sent UNUSED_PARAM)
|
|
|
- {
|
|
|
- // ignore possible errors and just keep receiving.
|
|
|
- startReceive();
|
|
|
- }
|
|
|
-private:
|
|
|
- const unsigned int iteration_;
|
|
|
- unsigned int n_received_;
|
|
|
- const bool async_send_;
|
|
|
-};
|
|
|
-}
|
|
|
-
|
|
|
-namespace isc {
|
|
|
-namespace bench {
|
|
|
-template<>
|
|
|
-void
|
|
|
-BenchMark<NativeSocketBenchMark>::tearDown() {
|
|
|
- target_.closeSocket();
|
|
|
-}
|
|
|
-
|
|
|
-template<>
|
|
|
-void
|
|
|
-BenchMark<ASIOSyncBenchMark>::tearDown() {
|
|
|
- target_.cleanup();
|
|
|
-}
|
|
|
-
|
|
|
-template<>
|
|
|
-void
|
|
|
-BenchMark<ASIOAsyncBenchMark>::tearDown() {
|
|
|
- target_.cleanup();
|
|
|
-}
|
|
|
-}
|
|
|
-}
|
|
|
-
|
|
|
-namespace {
|
|
|
-const int DEFAULT_PACKET_SIZE = 250; // arbitrary choice
|
|
|
-const int DEFAULT_ITERATION = 10000;
|
|
|
-const char* const DEFAULT_PORTSTR = "53530";
|
|
|
-
|
|
|
-void
|
|
|
-usage() {
|
|
|
- cerr << "Usage: netio_bench [-n iterations] [-p port] [-s packet_size]"
|
|
|
- << endl;
|
|
|
- exit (1);
|
|
|
-}
|
|
|
-}
|
|
|
-
|
|
|
-int
|
|
|
-main(int argc, char* argv[]) {
|
|
|
- int ch;
|
|
|
- int iteration = DEFAULT_ITERATION;
|
|
|
- int packet_size = DEFAULT_PACKET_SIZE;
|
|
|
-
|
|
|
- const char* portstr = DEFAULT_PORTSTR;
|
|
|
-
|
|
|
- while ((ch = getopt(argc, argv, "n:p:s:")) != -1) {
|
|
|
- switch (ch) {
|
|
|
- case 'n':
|
|
|
- iteration = atoi(optarg);
|
|
|
- break;
|
|
|
- case 'p':
|
|
|
- portstr = optarg;
|
|
|
- break;
|
|
|
- case 's':
|
|
|
- packet_size = atoi(optarg);
|
|
|
- break;
|
|
|
- case '?':
|
|
|
- default:
|
|
|
- usage();
|
|
|
- }
|
|
|
- }
|
|
|
- argc -= optind;
|
|
|
- argv += optind;
|
|
|
- if (argc > 0) {
|
|
|
- usage();
|
|
|
- }
|
|
|
-
|
|
|
- boost::asio::io_service io_service;
|
|
|
- const uint16_t portnum = static_cast<uint16_t>(atoi(portstr));
|
|
|
-
|
|
|
- cout << "Socket I/O benchmark using native socket API (IPv4)" << endl;
|
|
|
- NativeSocketBenchMark io_bench1(AF_INET, portstr, packet_size);
|
|
|
- BenchMark<NativeSocketBenchMark> bench1(iteration, io_bench1);
|
|
|
- bench1.run();
|
|
|
-
|
|
|
- cout << "Socket I/O benchmark using native socket API (IPv6)" << endl;
|
|
|
- NativeSocketBenchMark io_bench2(AF_INET6, portstr, packet_size);
|
|
|
- BenchMark<NativeSocketBenchMark> bench2(iteration, io_bench2);
|
|
|
- bench2.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using synchronous I/O (IPv4)" << endl;
|
|
|
- ASIOSyncBenchMark io_bench3(io_service, AF_INET, portnum, packet_size);
|
|
|
- BenchMark<ASIOSyncBenchMark> bench3(iteration, io_bench3);
|
|
|
- bench3.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using synchronous I/O (IPv6)" << endl;
|
|
|
- ASIOSyncBenchMark io_bench4(io_service, AF_INET6, portnum, packet_size);
|
|
|
- BenchMark<ASIOSyncBenchMark> bench4(iteration, io_bench4);
|
|
|
- bench4.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using asynchronous receive I/O (IPv4)" << endl;
|
|
|
- ASIOAsyncBenchMark io_bench5(io_service, AF_INET, portnum, packet_size,
|
|
|
- iteration, false);
|
|
|
- BenchMark<ASIOAsyncBenchMark> bench5(1, io_bench5);
|
|
|
- bench5.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using asynchronous receive I/O (IPv6)" << endl;
|
|
|
- ASIOAsyncBenchMark io_bench6(io_service, AF_INET6, portnum, packet_size,
|
|
|
- iteration, false);
|
|
|
- BenchMark<ASIOAsyncBenchMark> bench6(1, io_bench6);
|
|
|
- bench6.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using asynchronous send/receive I/O (IPv4)" << endl;
|
|
|
- ASIOAsyncBenchMark io_bench7(io_service, AF_INET, portnum, packet_size,
|
|
|
- iteration, true);
|
|
|
- BenchMark<ASIOAsyncBenchMark> bench7(1, io_bench7);
|
|
|
- bench7.run();
|
|
|
-
|
|
|
- cout << "ASIO benchmark using asynchronous send/receive I/O (IPv6)" << endl;
|
|
|
- ASIOAsyncBenchMark io_bench8(io_service, AF_INET6, portnum, packet_size,
|
|
|
- iteration, true);
|
|
|
- BenchMark<ASIOAsyncBenchMark> bench8(1, io_bench8);
|
|
|
- bench8.run();
|
|
|
-
|
|
|
- return (0);
|
|
|
-}
|