Browse Source

copy from the experimental branch

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac241@2139 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
e171bd88b1

+ 33 - 0
src/bin/auth/benchmarks/Makefile.am

@@ -0,0 +1,33 @@
+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

+ 388 - 0
src/bin/auth/benchmarks/netio_bench.cc

@@ -0,0 +1,388 @@
+// 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);
+}

+ 185 - 0
src/bin/auth/benchmarks/query_bench.cc

@@ -0,0 +1,185 @@
+// 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);
+}