query_bench.cc 9.47 KB
Newer Older
JINMEI Tatuya's avatar
JINMEI Tatuya committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
// 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.

#include <stdlib.h>

#include <iostream>
#include <vector>

#include <boost/shared_ptr.hpp>

#include <bench/benchmark.h>
#include <bench/benchmark_util.h>

#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/name.h>
#include <dns/question.h>
#include <dns/rrclass.h>

#include <xfr/xfrout_client.h>

#include <auth/auth_srv.h>
34
#include <auth/config.h>
35
#include <auth/query.h>
Jerry's avatar
Jerry committed
36

Michal Vaner's avatar
Michal Vaner committed
37
#include <asiolink/asiolink.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
38 39 40

using namespace std;
using namespace isc;
41
using namespace isc::data;
42
using namespace isc::auth;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
43 44 45
using namespace isc::dns;
using namespace isc::xfr;
using namespace isc::bench;
Michal Vaner's avatar
Michal Vaner committed
46
using namespace asiolink;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
47 48 49 50 51

namespace {
// Commonly used constant:
XfroutClient xfrout_client("dummy_path"); // path doesn't matter

Michal Vaner's avatar
Michal Vaner committed
52 53 54
// Just something to pass as the server to resume
class DummyServer : public DNSServer {
    public:
55 56
        virtual void operator()(asio::error_code, size_t) {}
        virtual void resume(const bool) {}
Michal Vaner's avatar
Michal Vaner committed
57
        virtual DNSServer* clone() {
58
            return (new DummyServer(*this));
Michal Vaner's avatar
Michal Vaner committed
59 60 61
        }
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
62
class QueryBenchMark {
63
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
64 65 66
    // Maintain dynamically generated objects via shared pointers because
    // QueryBenchMark objects will be copied.
    typedef boost::shared_ptr<AuthSrv> AuthSrvPtr;
67
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
68
    typedef boost::shared_ptr<const IOEndpoint> IOEndpointPtr;
69 70
protected:
    QueryBenchMark(const bool enable_cache,
Michal Vaner's avatar
Michal Vaner committed
71 72
                   const BenchQueries& queries, MessagePtr query_message,
                   OutputBufferPtr buffer) :
73
        server_(new AuthSrv(enable_cache, xfrout_client)),
JINMEI Tatuya's avatar
JINMEI Tatuya committed
74 75
        queries_(queries),
        query_message_(query_message),
Michal Vaner's avatar
Michal Vaner committed
76
        buffer_(buffer),
JINMEI Tatuya's avatar
JINMEI Tatuya committed
77 78 79 80
        dummy_socket(IOSocket::getDummyUDPSocket()),
        dummy_endpoint(IOEndpointPtr(IOEndpoint::create(IPPROTO_UDP,
                                                        IOAddress("192.0.2.1"),
                                                        5300)))
81 82
    {}
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
83 84 85
    unsigned int run() {
        BenchQueries::const_iterator query;
        const BenchQueries::const_iterator query_end = queries_.end();
Michal Vaner's avatar
Michal Vaner committed
86
        DummyServer server;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
87 88 89
        for (query = queries_.begin(); query != query_end; ++query) {
            IOMessage io_message(&(*query)[0], (*query).size(), dummy_socket,
                                 *dummy_endpoint);
Michal Vaner's avatar
Michal Vaner committed
90
            query_message_->clear(Message::PARSE);
91
            buffer_->clear();
Michal Vaner's avatar
Michal Vaner committed
92
            server_->processMessage(io_message, query_message_, buffer_,
93
                                    &server);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
94 95 96 97
        }

        return (queries_.size());
    }
98
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
99
    AuthSrvPtr server_;
100
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
101
    const BenchQueries& queries_;
Michal Vaner's avatar
Michal Vaner committed
102 103
    MessagePtr query_message_;
    OutputBufferPtr buffer_;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
104 105 106
    IOSocket& dummy_socket;
    IOEndpointPtr dummy_endpoint;
};
Michal Vaner's avatar
Michal Vaner committed
107

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
class Sqlite3QueryBenchMark  : public QueryBenchMark {
public:
    Sqlite3QueryBenchMark(const int cache_slots,
                          const char* const datasrc_file,
                          const BenchQueries& queries,
                          MessagePtr query_message,
                          OutputBufferPtr buffer) :
        QueryBenchMark(cache_slots >= 0 ? true : false, queries,
                       query_message, buffer)
    {
        if (cache_slots >= 0) {
            server_->setCacheSlots(cache_slots);
        }
        server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
                                                string(datasrc_file) + "\"}"));
    }
};

class MemoryQueryBenchMark  : public QueryBenchMark {
public:
    MemoryQueryBenchMark(const char* const zone_file,
                         const char* const zone_origin,
                          const BenchQueries& queries,
                          MessagePtr query_message,
                          OutputBufferPtr buffer) :
        QueryBenchMark(false, queries, query_message, buffer)
    {
        configureAuthServer(*server_,
                            Element::fromJSON(
                                "{\"datasources\": "
                                " [{\"type\": \"memory\","
                                "   \"zones\": [{\"origin\": \"" +
                                string(zone_origin) + "\","
                                "    \"file\": \"" +
                                string(zone_file) + "\"}]}]}"));
    }
};

void
printQPSResult(unsigned int iteration, double duration,
            double iteration_per_second)
{
    cout.precision(6);
    cout << "Processed " << iteration << " queries in "
         << fixed << duration << "s";
    cout.precision(2);
    cout << " (" << fixed << iteration_per_second << "qps)" << endl;
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
156 157 158 159 160 161
}

namespace isc {
namespace bench {
template<>
void
162 163 164 165 166 167 168 169
BenchMark<Sqlite3QueryBenchMark>::printResult() const {
    printQPSResult(getIteration(), getDuration(), getIterationPerSecond());
}

template<>
void
BenchMark<MemoryQueryBenchMark>::printResult() const {
    printQPSResult(getIteration(), getDuration(), getIterationPerSecond());
JINMEI Tatuya's avatar
JINMEI Tatuya committed
170 171 172 173 174
}
}
}

namespace {
175 176 177 178 179 180
const int ITERATION_DEFAULT = 1;
enum DataSrcType {
    SQLITE3,
    MEMORY
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
181 182
void
usage() {
183 184 185 186 187 188 189 190 191 192 193
    cerr <<
        "Usage: query_bench [-n iterations] [-t datasrc_type] [-o origin] "
        "datasrc_file query_datafile\n"
        "  -n Number of iterations per test case (default: "
         << ITERATION_DEFAULT << ")\n"
        "  -t Type of data source: sqlite3|memory (default: sqlite3)\n"
        "  -o Origin name of datasrc_file necessary for \"memory\", "
        "ignored for others\n"
        "  datasrc_file: sqlite3 DB file for \"sqlite3\", "
        "textual master file for \"memory\" datasrc\n"
        "  query_datafile: queryperf style input data"
JINMEI Tatuya's avatar
JINMEI Tatuya committed
194 195 196 197 198 199 200 201
         << endl;
    exit (1);
}
}

int
main(int argc, char* argv[]) {
    int ch;
202 203 204 205
    int iteration = ITERATION_DEFAULT;
    const char* opt_datasrc_type = "sqlite3";
    const char* origin = NULL;
    while ((ch = getopt(argc, argv, "n:t:o:")) != -1) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
206 207 208 209
        switch (ch) {
        case 'n':
            iteration = atoi(optarg);
            break;
210 211 212 213 214 215
        case 't':
            opt_datasrc_type = optarg;
            break;
        case 'o':
            origin = optarg;
            break;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
216 217 218 219 220 221 222 223 224 225 226 227 228
        case '?':
        default:
            usage();
        }
    }
    argc -= optind;
    argv += optind;
    if (argc < 2) {
        usage();
    }
    const char* const datasrc_file = argv[0];
    const char* const query_data_file = argv[1];

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
    DataSrcType datasrc_type = SQLITE3;
    if (strcmp(opt_datasrc_type, "sqlite3") == 0) {
        ;                       // no need to override
    } else if (strcmp(opt_datasrc_type, "memory") == 0) {
        datasrc_type = MEMORY;
    } else {
        cerr << "Unknown data source type: " << datasrc_type << endl;
        return (1);
    }

    if (datasrc_type == MEMORY && origin == NULL) {
        cerr << "'-o Origin' is missing for memory data source " << endl;
        return (1);
    }

JINMEI Tatuya's avatar
JINMEI Tatuya committed
244 245
    BenchQueries queries;
    loadQueryData(query_data_file, queries, RRClass::IN());
Michal Vaner's avatar
Michal Vaner committed
246 247
    OutputBufferPtr buffer(new OutputBuffer(4096));
    MessagePtr message(new Message(Message::PARSE));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
248 249 250

    cout << "Parameters:" << endl;
    cout << "  Iterations: " << iteration << endl;
251 252 253 254 255
    cout << "  Data Source: type=" << opt_datasrc_type << ", file=" <<
        datasrc_file << endl;
    if (origin != NULL) {
        cout << "  Origin: " << origin << endl;
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
256 257 258
    cout << "  Query data: file=" << query_data_file << " (" << queries.size()
         << " queries)" << endl << endl;

259 260 261 262 263 264 265
    switch (datasrc_type) {
    case SQLITE3:
        cout << "Benchmark enabling Hot Spot Cache with unlimited slots "
             << endl;
        BenchMark<Sqlite3QueryBenchMark>(
            iteration, Sqlite3QueryBenchMark(0, datasrc_file, queries,
                                             message, buffer));
266

267 268 269 270
        cout << "Benchmark enabling Hot Spot Cache with 10*#queries slots "
             << endl;
        BenchMark<Sqlite3QueryBenchMark>(
            iteration, Sqlite3QueryBenchMark(10 * queries.size(), datasrc_file,
Michal Vaner's avatar
Michal Vaner committed
271
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
272

273 274 275 276
        cout << "Benchmark enabling Hot Spot Cache with #queries/2 slots "
             << endl;
        BenchMark<Sqlite3QueryBenchMark>(
            iteration, Sqlite3QueryBenchMark(queries.size() / 2, datasrc_file,
Michal Vaner's avatar
Michal Vaner committed
277
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
278

279 280 281 282 283 284 285 286 287 288 289 290
        cout << "Benchmark disabling Hot Spot Cache" << endl;
        BenchMark<Sqlite3QueryBenchMark>(
            iteration, Sqlite3QueryBenchMark(-1, datasrc_file, queries,
                                             message, buffer));
        break;
    case MEMORY:
        cout << "Benchmark with In Memory Data Source" << endl;
        BenchMark<MemoryQueryBenchMark>(
            iteration, MemoryQueryBenchMark(datasrc_file, origin, queries,
                                            message, buffer));
        break;
    }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
291 292 293

    return (0);
}