mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 05:55:28 +00:00
removed additional benchmark examples for now.
updated the doxygen config to include the benchmark docs. git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac241@2500 e5f2f494-b856-4b98-b285-d166d9295462
This commit is contained in:
@@ -568,7 +568,7 @@ WARN_LOGFILE =
|
|||||||
# directories like "/usr/src/myproject". Separate the files or directories
|
# directories like "/usr/src/myproject". Separate the files or directories
|
||||||
# with spaces.
|
# with spaces.
|
||||||
|
|
||||||
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions
|
INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/bench
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||||
|
@@ -1,33 +0,0 @@
|
|||||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
|
||||||
AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
|
|
||||||
|
|
||||||
CLEANFILES = *.gcno *.gcda
|
|
||||||
|
|
||||||
noinst_PROGRAMS = query_bench
|
|
||||||
if HAVE_BOOST_SYSTEM
|
|
||||||
noinst_PROGRAMS += netio_bench
|
|
||||||
endif
|
|
||||||
query_bench_SOURCES = query_bench.cc
|
|
||||||
query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
|
|
||||||
query_bench_SOURCES += ../normalquestion.h ../normalquestion.cc
|
|
||||||
query_bench_SOURCES += ../rbt_datasrc.h ../rbt_datasrc.cc
|
|
||||||
query_bench_SOURCES += ../loadzone.h ../loadzone.cc
|
|
||||||
|
|
||||||
query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns.la
|
|
||||||
query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
|
|
||||||
query_bench_LDADD += $(top_builddir)/src/lib/bench/libbench.la
|
|
||||||
query_bench_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
|
|
||||||
query_bench_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
|
|
||||||
query_bench_LDADD += $(top_builddir)/src/lib/cc/libcc.a
|
|
||||||
query_bench_LDADD += $(SQLITE_LIBS)
|
|
||||||
if HAVE_BOOST_SYSTEM
|
|
||||||
query_bench_LDFLAGS = $(AM_LDFLAGS) $(BOOST_LDFLAGS)
|
|
||||||
query_bench_LDADD += $(BOOST_SYSTEM_LIB)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if HAVE_BOOST_SYSTEM
|
|
||||||
netio_bench_SOURCES = netio_bench.cc
|
|
||||||
netio_bench_LDFLAGS = $(AM_LDFLAGS) $(BOOST_LDFLAGS)
|
|
||||||
netio_bench_LDADD = $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
|
|
||||||
netio_bench_LDADD += $(BOOST_SYSTEM_LIB)
|
|
||||||
endif
|
|
@@ -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);
|
|
||||||
}
|
|
@@ -1,185 +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 <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <bench/benchmark.h>
|
|
||||||
#include <bench/benchmark_util.h>
|
|
||||||
|
|
||||||
#include <dns/buffer.h>
|
|
||||||
#include <dns/message.h>
|
|
||||||
#include <dns/messagerenderer.h>
|
|
||||||
#include <dns/name.h>
|
|
||||||
#include <dns/question.h>
|
|
||||||
#include <dns/rrclass.h>
|
|
||||||
|
|
||||||
#include <auth/auth_srv.h>
|
|
||||||
#include <auth/rbt_datasrc.h>
|
|
||||||
#include <auth/loadzone.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace isc;
|
|
||||||
using namespace isc::dns;
|
|
||||||
using namespace isc::bench;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class QueryBenchMark {
|
|
||||||
public:
|
|
||||||
QueryBenchMark(AuthSrv& server, const BenchQueries& queries,
|
|
||||||
MessageRenderer* renderer, const bool need_to_write) :
|
|
||||||
server_(server), queries_(queries), query_message_(Message::PARSE),
|
|
||||||
renderer_(renderer), null_fd_(-1), need_to_write_(need_to_write)
|
|
||||||
{
|
|
||||||
null_fd_ = open("/dev/null", O_RDWR);
|
|
||||||
if (null_fd_ < 0) {
|
|
||||||
isc_throw(Exception, "failed to open output file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
~QueryBenchMark() {
|
|
||||||
if (null_fd_ >= 0) {
|
|
||||||
close(null_fd_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned int run() {
|
|
||||||
BenchQueries::const_iterator query;
|
|
||||||
const BenchQueries::const_iterator query_end = queries_.end();
|
|
||||||
for (query = queries_.begin(); query != query_end; ++query) {
|
|
||||||
InputBuffer buffer(&(*query)[0], (*query).size());
|
|
||||||
query_message_.clear(Message::PARSE);
|
|
||||||
renderer_->clear();
|
|
||||||
server_.processMessage(buffer, query_message_, *renderer_, true);
|
|
||||||
if (need_to_write_) {
|
|
||||||
write(null_fd_, renderer_->getData(), renderer_->getLength());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (queries_.size());
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
AuthSrv& server_;
|
|
||||||
const BenchQueries& queries_;
|
|
||||||
Message query_message_;
|
|
||||||
MessageRenderer* renderer_;
|
|
||||||
int null_fd_;
|
|
||||||
const bool need_to_write_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace isc {
|
|
||||||
namespace bench {
|
|
||||||
template<>
|
|
||||||
void
|
|
||||||
BenchMark<QueryBenchMark>::printResult() const {
|
|
||||||
cout.precision(6);
|
|
||||||
cout << "Processed " << getIteration() << " queries in "
|
|
||||||
<< fixed << getDuration() << "s";
|
|
||||||
cout.precision(2);
|
|
||||||
cout << " (" << fixed << getIterationPerSecond() << "qps)" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void
|
|
||||||
usage() {
|
|
||||||
cerr << "Usage: query_bench [-n iterations] zone_file "
|
|
||||||
"zone_origin query_datafile" << endl;
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char* argv[]) {
|
|
||||||
int ch;
|
|
||||||
int iteration = 1;
|
|
||||||
while ((ch = getopt(argc, argv, "n:")) != -1) {
|
|
||||||
switch (ch) {
|
|
||||||
case 'n':
|
|
||||||
iteration = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
if (argc < 3) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
const char* const zone_file = argv[0];
|
|
||||||
const char* const origin = argv[1];
|
|
||||||
const char* const query_data_file = argv[2];
|
|
||||||
|
|
||||||
// Prepare the database
|
|
||||||
RbtDataSrc* datasrc = new RbtDataSrc(Name(origin));
|
|
||||||
loadZoneFile(zone_file, datasrc);
|
|
||||||
|
|
||||||
// Load queries
|
|
||||||
BenchQueries queries;
|
|
||||||
loadQueryData(query_data_file, queries, RRClass::IN());
|
|
||||||
|
|
||||||
// Create server object.
|
|
||||||
// The current experimental implementation depends on some environment
|
|
||||||
// variables, so we configure them before constructing a new server.
|
|
||||||
setenv("ZONEFILE", zone_file, 1);
|
|
||||||
setenv("DBORIGIN", origin, 1);
|
|
||||||
AuthSrv* auth_server = new AuthSrv;
|
|
||||||
|
|
||||||
// Create different types of message renderer
|
|
||||||
CompressOffsetTable offset_table_;
|
|
||||||
OutputBuffer buffer(4096);
|
|
||||||
MessageRenderer standard_renderer(buffer, &offset_table_);
|
|
||||||
MessageRenderer optimized_renderer(4096, &offset_table_);
|
|
||||||
|
|
||||||
// Perform benchmark test and dump the result
|
|
||||||
cout << "Query processing benchmark with standard renderer, "
|
|
||||||
"no write to device " << endl;
|
|
||||||
QueryBenchMark query_bench1(*auth_server, queries, &standard_renderer,
|
|
||||||
false);
|
|
||||||
BenchMark<QueryBenchMark> bench1(iteration, query_bench1);
|
|
||||||
bench1.run();
|
|
||||||
|
|
||||||
cout << "Query processing benchmark with standard renderer, "
|
|
||||||
"write to device " << endl;
|
|
||||||
QueryBenchMark query_bench2(*auth_server, queries, &standard_renderer,
|
|
||||||
true);
|
|
||||||
BenchMark<QueryBenchMark> bench2(iteration, query_bench2);
|
|
||||||
bench2.run();
|
|
||||||
|
|
||||||
cout << "Query processing benchmark with optimized renderer, "
|
|
||||||
"no write to device " << endl;
|
|
||||||
QueryBenchMark query_bench3(*auth_server, queries, &optimized_renderer,
|
|
||||||
false);
|
|
||||||
BenchMark<QueryBenchMark> bench3(iteration, query_bench3);
|
|
||||||
bench3.run();
|
|
||||||
|
|
||||||
cout << "Query processing benchmark with optimized renderer, "
|
|
||||||
"write to device " << endl;
|
|
||||||
QueryBenchMark query_bench4(*auth_server, queries, &optimized_renderer,
|
|
||||||
true);
|
|
||||||
BenchMark<QueryBenchMark> bench4(iteration, query_bench4);
|
|
||||||
bench4.run();
|
|
||||||
|
|
||||||
delete auth_server;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
@@ -1,7 +0,0 @@
|
|||||||
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
|
|
||||||
|
|
||||||
CLEANFILES = *.gcno *.gcda
|
|
||||||
|
|
||||||
noinst_PROGRAMS = buffer_bench
|
|
||||||
buffer_bench_SOURCES = buffer_bench.cc
|
|
||||||
buffer_bench_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
|
|
@@ -1,235 +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 <cassert>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <bench/benchmark.h>
|
|
||||||
|
|
||||||
#include <exceptions/exceptions.h>
|
|
||||||
|
|
||||||
#include <dns/buffer.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace isc;
|
|
||||||
using namespace isc::dns;
|
|
||||||
using namespace isc::bench;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
// A simplified buffer implementation using plain old array for comparison
|
|
||||||
// (omitting some validations for brevity)
|
|
||||||
class ArrayOutputBuffer {
|
|
||||||
public:
|
|
||||||
ArrayOutputBuffer(size_t n) : limit_(n) {
|
|
||||||
data_ = new uint8_t[n];
|
|
||||||
}
|
|
||||||
~ArrayOutputBuffer() {
|
|
||||||
delete[] data_;
|
|
||||||
}
|
|
||||||
void clear() { index_ = 0; }
|
|
||||||
void writeUint8(const uint8_t data) {
|
|
||||||
if (index_ + 1 > limit_) {
|
|
||||||
isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
|
|
||||||
}
|
|
||||||
data_[index_] = data;
|
|
||||||
++index_;
|
|
||||||
}
|
|
||||||
void writeUint16(const uint16_t data) {
|
|
||||||
if (index_ + 2 > limit_) {
|
|
||||||
isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
|
|
||||||
}
|
|
||||||
const uint8_t net_data[2] = { (data & 0xff00U) >> 8, data & 0x00ffU };
|
|
||||||
memcpy(&data_[index_], net_data, 2);
|
|
||||||
index_ += 2;
|
|
||||||
}
|
|
||||||
void writeUint32(const uint32_t data) {
|
|
||||||
if (index_ + 4 > limit_) {
|
|
||||||
isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
|
|
||||||
}
|
|
||||||
const uint8_t net_data[4] = { (data & 0xff000000) >> 24,
|
|
||||||
(data & 0x00ff0000) >> 16,
|
|
||||||
(data & 0x0000ff00) >> 8,
|
|
||||||
data & 0x000000ff };
|
|
||||||
memcpy(&data_[index_], net_data, 4);
|
|
||||||
index_ += 4;
|
|
||||||
}
|
|
||||||
void writeData(const void *data, const size_t len) {
|
|
||||||
if (len > limit_ || index_ > (limit_ - len)) {
|
|
||||||
isc_throw(InvalidBufferPosition, "write beyond the end of buffer");
|
|
||||||
}
|
|
||||||
memcpy(&data_[index_], data, len);
|
|
||||||
index_ += len;
|
|
||||||
}
|
|
||||||
size_t getLength() const { return (index_); }
|
|
||||||
const void* getData() const { return (data_); }
|
|
||||||
private:
|
|
||||||
const size_t limit_;
|
|
||||||
size_t index_;
|
|
||||||
uint8_t* data_;
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t check_data[] = {
|
|
||||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10, 192, 0, 2, 1,
|
|
||||||
0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x10,
|
|
||||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34 };
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class BufferBenchMark {
|
|
||||||
public:
|
|
||||||
BufferBenchMark(T& buffer, const bool use_writedata) :
|
|
||||||
buffer_(buffer), use_writedata_(use_writedata) {}
|
|
||||||
~BufferBenchMark() {}
|
|
||||||
unsigned int run() {
|
|
||||||
// This test emulates writing 20 RR-like objects into the given buffer.
|
|
||||||
buffer_.clear();
|
|
||||||
for (int i = 0; i < 20; ++i) {
|
|
||||||
buffer_.writeUint16(rrtype_val_);
|
|
||||||
buffer_.writeUint16(rrclass_val_);
|
|
||||||
buffer_.writeUint32(rrttl_val_);
|
|
||||||
|
|
||||||
const uint8_t* data;
|
|
||||||
size_t datalen;
|
|
||||||
if ((i % 2) == 0) {
|
|
||||||
data = data_a;
|
|
||||||
datalen = sizeof(data_a);
|
|
||||||
} else {
|
|
||||||
data = data_aaaa;
|
|
||||||
datalen = sizeof(data_aaaa);
|
|
||||||
}
|
|
||||||
if (use_writedata_) {
|
|
||||||
buffer_.writeData(data, datalen);
|
|
||||||
} else {
|
|
||||||
for (int j = 0; j < datalen; ++j) {
|
|
||||||
buffer_.writeUint8(data[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
bool checkData() const {
|
|
||||||
if (buffer_.getLength() < sizeof(check_data)) {
|
|
||||||
isc_throw(Exception, "written buffer is too short: " <<
|
|
||||||
buffer_.getLength());
|
|
||||||
}
|
|
||||||
if (memcmp(buffer_.getData(), check_data, sizeof(check_data)) != 0) {
|
|
||||||
isc_throw(Exception, "data mismatch");
|
|
||||||
}
|
|
||||||
return (true);
|
|
||||||
}
|
|
||||||
bool isUsingWriteData() const { return (use_writedata_); }
|
|
||||||
private:
|
|
||||||
static const uint16_t rrtype_val_ = 1;
|
|
||||||
static const uint16_t rrclass_val_ = 1;
|
|
||||||
static const uint32_t rrttl_val_ = 3600;
|
|
||||||
static const uint8_t data_a[4];
|
|
||||||
static const uint8_t data_aaaa[16];
|
|
||||||
T& buffer_;
|
|
||||||
const bool use_writedata_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const uint8_t BufferBenchMark<T>::data_a[] = { 192, 0, 2, 1 };
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
const uint8_t BufferBenchMark<T>::data_aaaa[] = {
|
|
||||||
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34 };
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace isc {
|
|
||||||
namespace bench {
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
BenchMark<BufferBenchMark<OutputBuffer> >::setUp() {
|
|
||||||
cout << "Benchmark for write operations using libdns OutputBuffer and "
|
|
||||||
<< (target_.isUsingWriteData() ? "writeData:" :
|
|
||||||
"explicit loop:") << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
BenchMark<BufferBenchMark<OutputBuffer> >::tearDown() {
|
|
||||||
assert(target_.checkData());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
BenchMark<BufferBenchMark<ArrayOutputBuffer> >::setUp() {
|
|
||||||
cout << "Benchmark for write operations using plain old array and "
|
|
||||||
<< (target_.isUsingWriteData() ? "writeData:" :
|
|
||||||
"explicit loop:") << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
void
|
|
||||||
BenchMark<BufferBenchMark<ArrayOutputBuffer> >::tearDown() {
|
|
||||||
assert(target_.checkData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
void
|
|
||||||
usage() {
|
|
||||||
cerr << "Usage: buffer_bench [-n iterations]" << endl;
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char* argv[]) {
|
|
||||||
int ch;
|
|
||||||
int iteration = 100000;
|
|
||||||
while ((ch = getopt(argc, argv, "n:")) != -1) {
|
|
||||||
switch (ch) {
|
|
||||||
case 'n':
|
|
||||||
iteration = atoi(optarg);
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argc -= optind;
|
|
||||||
if (argc > 0) {
|
|
||||||
usage();
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputBuffer dns_buffer(4096);
|
|
||||||
BufferBenchMark<OutputBuffer> buffer_bench(dns_buffer, true);
|
|
||||||
BenchMark<BufferBenchMark<OutputBuffer> > bench1(iteration, buffer_bench);
|
|
||||||
bench1.run();
|
|
||||||
|
|
||||||
ArrayOutputBuffer array_buffer(4096);
|
|
||||||
BufferBenchMark<ArrayOutputBuffer> array_bench(array_buffer, true);
|
|
||||||
BenchMark<BufferBenchMark<ArrayOutputBuffer> > bench2(iteration,
|
|
||||||
array_bench);
|
|
||||||
bench2.run();
|
|
||||||
|
|
||||||
BufferBenchMark<OutputBuffer> buffer_bench2(dns_buffer, false);
|
|
||||||
BenchMark<BufferBenchMark<OutputBuffer> > bench3(iteration, buffer_bench2);
|
|
||||||
bench3.run();
|
|
||||||
|
|
||||||
BufferBenchMark<ArrayOutputBuffer> array_bench2(array_buffer, false);
|
|
||||||
BenchMark<BufferBenchMark<ArrayOutputBuffer> > bench4(iteration,
|
|
||||||
array_bench2);
|
|
||||||
bench4.run();
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
Reference in New Issue
Block a user