query_bench.cc 9.49 KB
Newer Older
JINMEI Tatuya's avatar
JINMEI Tatuya committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 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.

15 16
#include <config.h>

JINMEI Tatuya's avatar
JINMEI Tatuya committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#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>
36
#include <auth/auth_config.h>
37
#include <auth/query.h>
Jerry's avatar
Jerry committed
38

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return (0);
}