query_bench.cc 9.8 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,
Michal Vaner's avatar
Michal Vaner committed
79 80
                   const BenchQueries& queries, MessagePtr query_message,
                   OutputBufferPtr 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);
Michal Vaner's avatar
Michal Vaner committed
98
            query_message_->clear(Message::PARSE);
99
            buffer_->clear();
100
            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_;
Michal Vaner's avatar
Michal Vaner committed
110 111
    MessagePtr query_message_;
    OutputBufferPtr 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 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 158 159 160 161 162 163
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
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());
Michal Vaner's avatar
Michal Vaner committed
258 259
    OutputBufferPtr buffer(new OutputBuffer(4096));
    MessagePtr message(new 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);
}