rdatarender_bench.cc 5.98 KB
Newer Older
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
// 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 <iostream>
#include <fstream>
#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

#include <bench/benchmark.h>

#include <dns/buffer.h>
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdatafields.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>

using namespace std;
using namespace isc::bench;
using namespace isc::dns;
using namespace isc::dns::rdata;

namespace {
// This templated benchmark class is constructed with a vector of Rdata-like
// (pointer) objects which should have a "toWire()" method.  In its run(),
// it calls toWire() for each element of the vector.
template <typename T>
class RdataRenderBenchMark {
public:
    RdataRenderBenchMark(const vector<T>& dataset) :
        dataset_(dataset), buffer_(4096), renderer_(buffer_)
    {}
    unsigned int run() {
        typename vector<T>::const_iterator data;
        typename vector<T>::const_iterator data_end = dataset_.end();
        for (data = dataset_.begin(); data != data_end; ++data) {
            renderer_.clear();
            (*data)->toWire(renderer_);
        }
        return (dataset_.size());
    }
private:
    const vector<T>& dataset_;
    OutputBuffer buffer_;
    MessageRenderer renderer_;
};

// This supplemental class emulates an RRset like class that internally
// uses RdataFields.  On construction it stores RDATA information in the
// form of RdataFields fields.  Its toWire() method restores the data as
// an RdataFields object for the rendering.
class RdataFieldsStore {
public:
    RdataFieldsStore(ConstRdataPtr rdata) {
        const RdataFields fields(*rdata);

        nspecs_ = fields.getFieldCount();
        spec_store_.resize(nspecs_ * sizeof(RdataFields::FieldSpec));
        void* cp_spec = &spec_store_[0];
        memcpy(cp_spec, fields.getFieldSpecData(), spec_store_.size());
        spec_ptr_ = static_cast<RdataFields::FieldSpec*>(cp_spec);

        data_length_ = fields.getDataLength();
        data_store_.assign(fields.getData(), fields.getData() + data_length_);
        data_ptr_ = &data_store_[0];
    }
    void toWire(MessageRenderer& renderer) const {
        RdataFields(spec_ptr_, nspecs_,
                    data_ptr_, data_length_).toWire(renderer);
    }
private:
    vector<unsigned char> spec_store_;
    const RdataFields::FieldSpec* spec_ptr_;
    unsigned int nspecs_;
    vector<uint8_t> data_store_;
    const uint8_t* data_ptr_;
    size_t data_length_;
};

// We wouldn't necessarily have to use a shared pointer, but it's easier
// to use pointer-like values to adjust them with the RdataRenderBenchMark
// template.
typedef boost::shared_ptr<const RdataFieldsStore> ConstRdataFieldsStorePtr;

void
readInputFile(const char* const input_file, vector<ConstRdataPtr>& rdata_sets,
              vector<ConstRdataFieldsStorePtr>& fields_sets)
{
    ifstream ifs;
    ifs.open(input_file, ios_base::in);
    if ((ifs.rdstate() & istream::failbit) != 0) {
        cerr << "Failed to read input file: " << input_file << endl;
        exit (1);
    }
    string line;
    unsigned int linenum = 0;
    while (getline(ifs, line), !ifs.eof()) {
        ++linenum;
        if (ifs.bad() || ifs.fail()) {
            cerr << "Unexpected input at line " << linenum << endl;
            exit (1);
        }
        if (line.empty() || line[0] == '#') {
            continue;           // skip comment and blank lines
        }
        istringstream iss(line);
        string rrclass_string, rrtype_string;
        stringbuf rdatabuf;
        iss >> rrclass_string >> rrtype_string >> &rdatabuf;
        if (iss.bad() || iss.fail()) {
            cerr << "Unexpected input at line " << linenum << endl;
            exit (1);
        }
        ConstRdataPtr rdata = createRdata(RRType(rrtype_string),
                                          RRClass(rrclass_string),
                                          rdatabuf.str());
        rdata_sets.push_back(rdata);
        fields_sets.push_back(ConstRdataFieldsStorePtr(
                                  new RdataFieldsStore(rdata)));
    }
    ifs.close();
}

void
usage() {
    cerr << "Usage: rdatafields_bench [-n iterations] input_file" << endl;
    exit (1);
}
}

int
main(int argc, char* argv[]) {
    int ch;
    int iteration = 10000;
    while ((ch = getopt(argc, argv, "n:")) != -1) {
        switch (ch) {
        case 'n':
            iteration = atoi(optarg);
            break;
        case '?':
        default:
            usage();
        }
    }
    argc -= optind;
    argv += optind;
    if (argc < 1) {
        usage();
    }
    const char* const input_file = argv[0];

    vector<ConstRdataPtr> rdata_sets;
    vector<ConstRdataFieldsStorePtr> fields_sets;

    readInputFile(input_file, rdata_sets, fields_sets);

    cout << "Parameters:" << endl;
    cout << "  Iterations: " << iteration << endl;
    cout << "  Input File: " << input_file << endl;

    typedef RdataRenderBenchMark<ConstRdataPtr> RdataBenchMark;
    cout << "Benchmark for rendering with standard Rdata" << endl;
    BenchMark<RdataBenchMark>(iteration, RdataBenchMark(rdata_sets));

    typedef RdataRenderBenchMark<ConstRdataFieldsStorePtr> FieldsBenchMark;
    cout << "Benchmark for rendering with RdataFields" << endl;
    BenchMark<FieldsBenchMark>(iteration, FieldsBenchMark(fields_sets));

    return (0);
}