query_bench.cc 9.74 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
#include <stdlib.h>

#include <iostream>
#include <vector>

#include <boost/shared_ptr.hpp>

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

27
#include <util/buffer.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
28 29 30 31 32
#include <dns/message.h>
#include <dns/name.h>
#include <dns/question.h>
#include <dns/rrclass.h>

33 34
#include <log/logger_support.h>

JINMEI Tatuya's avatar
JINMEI Tatuya committed
35 36 37
#include <xfr/xfrout_client.h>

#include <auth/auth_srv.h>
38
#include <auth/auth_config.h>
39
#include <auth/query.h>
Jerry's avatar
Jerry committed
40

41
#include <asiodns/asiodns.h>
Michal Vaner's avatar
Michal Vaner committed
42
#include <asiolink/asiolink.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
43 44 45

using namespace std;
using namespace isc;
46
using namespace isc::data;
47
using namespace isc::auth;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
48
using namespace isc::dns;
49
using namespace isc::log;
50
using namespace isc::util;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
51 52
using namespace isc::xfr;
using namespace isc::bench;
53 54
using namespace isc::asiodns;
using namespace isc::asiolink;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
55 56 57 58 59

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

Michal Vaner's avatar
Michal Vaner committed
60 61 62
// Just something to pass as the server to resume
class DummyServer : public DNSServer {
    public:
63 64
        virtual void operator()(asio::error_code, size_t) {}
        virtual void resume(const bool) {}
Michal Vaner's avatar
Michal Vaner committed
65
        virtual DNSServer* clone() {
66
            return (new DummyServer(*this));
Michal Vaner's avatar
Michal Vaner committed
67 68 69
        }
};

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

        return (queries_.size());
    }
106
protected:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
107
    AuthSrvPtr server_;
108
private:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
109
    const BenchQueries& queries_;
110 111
    Message& query_message_;
    OutputBuffer& buffer_;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
112 113 114
    IOSocket& dummy_socket;
    IOEndpointPtr dummy_endpoint;
};
Michal Vaner's avatar
Michal Vaner committed
115

116 117 118 119 120
class Sqlite3QueryBenchMark  : public QueryBenchMark {
public:
    Sqlite3QueryBenchMark(const int cache_slots,
                          const char* const datasrc_file,
                          const BenchQueries& queries,
121 122
                          Message& query_message,
                          OutputBuffer& buffer) :
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
        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,
139 140
                          Message& query_message,
                          OutputBuffer& buffer) :
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        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
164 165 166 167 168 169
}

namespace isc {
namespace bench {
template<>
void
170 171 172 173 174 175 176 177
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
178 179 180 181 182
}
}
}

namespace {
183 184 185 186 187 188
const int ITERATION_DEFAULT = 1;
enum DataSrcType {
    SQLITE3,
    MEMORY
};

JINMEI Tatuya's avatar
JINMEI Tatuya committed
189 190
void
usage() {
191 192 193 194 195 196 197 198 199 200 201
    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
202 203 204 205 206 207 208 209
         << endl;
    exit (1);
}
}

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

237 238 239 240
    // We disable logging to avoid unwanted noise. (We may eventually want to
    // make it more configurable)
    initLogger("query-bench", isc::log::NONE);

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
    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
256 257
    BenchQueries queries;
    loadQueryData(query_data_file, queries, RRClass::IN());
258 259
    OutputBuffer buffer(4096);
    Message message(Message::PARSE);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
260 261 262

    cout << "Parameters:" << endl;
    cout << "  Iterations: " << iteration << endl;
263 264 265 266 267
    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
268 269 270
    cout << "  Query data: file=" << query_data_file << " (" << queries.size()
         << " queries)" << endl << endl;

271 272 273 274 275 276 277
    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));
278

279 280 281 282
        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
283
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
284

285 286 287 288
        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
289
                                             queries, message, buffer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
290

291 292 293 294 295 296 297 298 299 300 301 302
        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
303 304 305

    return (0);
}