query_bench.cc 9.5 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
// 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>

25
#include <util/io/buffer.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
26 27 28 29 30 31 32 33
#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
using namespace isc::dns;
44
using namespace isc::util::io;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
45 46
using namespace isc::xfr;
using namespace isc::bench;
Michal Vaner's avatar
Michal Vaner committed
47
using namespace asiolink;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
48 49 50 51 52

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

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

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

        return (queries_.size());
    }
99
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
100
    AuthSrvPtr server_;
101
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
102
    const BenchQueries& queries_;
Michal Vaner's avatar
Michal Vaner committed
103 104
    MessagePtr query_message_;
    OutputBufferPtr buffer_;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
105 106 107
    IOSocket& dummy_socket;
    IOEndpointPtr dummy_endpoint;
};
Michal Vaner's avatar
Michal Vaner committed
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 156
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
157 158 159 160 161 162
}

namespace isc {
namespace bench {
template<>
void
163 164 165 166 167 168 169 170
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
171 172 173 174 175
}
}
}

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

JINMEI Tatuya's avatar
JINMEI Tatuya committed
182 183
void
usage() {
184 185 186 187 188 189 190 191 192 193 194
    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
195 196 197 198 199 200 201 202
         << endl;
    exit (1);
}
}

int
main(int argc, char* argv[]) {
    int ch;
203 204 205 206
    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
207 208 209 210
        switch (ch) {
        case 'n':
            iteration = atoi(optarg);
            break;
211 212 213 214 215 216
        case 't':
            opt_datasrc_type = optarg;
            break;
        case 'o':
            origin = optarg;
            break;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
217 218 219 220 221 222 223 224 225 226 227 228 229
        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];

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    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
245 246
    BenchQueries queries;
    loadQueryData(query_data_file, queries, RRClass::IN());
Michal Vaner's avatar
Michal Vaner committed
247 248
    OutputBufferPtr buffer(new OutputBuffer(4096));
    MessagePtr message(new Message(Message::PARSE));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
249 250 251

    cout << "Parameters:" << endl;
    cout << "  Iterations: " << iteration << endl;
252 253 254 255 256
    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
257 258 259
    cout << "  Query data: file=" << query_data_file << " (" << queries.size()
         << " queries)" << endl << endl;

260 261 262 263 264 265 266
    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));
267

268 269 270 271
        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
272
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
273

274 275 276 277
        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
278
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
279

280 281 282 283 284 285 286 287 288 289 290 291
        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
292 293 294

    return (0);
}