|
@@ -0,0 +1,176 @@
|
|
|
+// Copyright (C) 2012 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 <bench/benchmark.h>
|
|
|
+
|
|
|
+#include <dns/name.h>
|
|
|
+#include <dns/messagerenderer.h>
|
|
|
+#include <dns/oldmessagerenderer.h>
|
|
|
+
|
|
|
+#include <cassert>
|
|
|
+#include <vector>
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+using namespace isc::util;
|
|
|
+using namespace isc::bench;
|
|
|
+using namespace isc::dns;
|
|
|
+
|
|
|
+namespace {
|
|
|
+// This templated test performs rendering given set of names using
|
|
|
+// a given (templated) MessageRenderer implementation. We can check the
|
|
|
+// performance when we modify the renderer implementation by comparing the
|
|
|
+// old and new implementation for the same data.
|
|
|
+template <typename T>
|
|
|
+class MessageRendererBenchMark {
|
|
|
+public:
|
|
|
+ MessageRendererBenchMark(const vector<Name>& names) :
|
|
|
+ names_(names)
|
|
|
+ {}
|
|
|
+ unsigned int run() {
|
|
|
+ renderer_.clear();
|
|
|
+ vector<Name>::const_iterator it = names_.begin();
|
|
|
+ const vector<Name>::const_iterator it_end = names_.end();
|
|
|
+ for (; it != it_end; ++it) {
|
|
|
+ renderer_.writeName(*it);
|
|
|
+ }
|
|
|
+ // Make sure truncation didn't accidentally happen.
|
|
|
+ assert(!renderer_.isTruncated());
|
|
|
+ return (names_.size());
|
|
|
+ }
|
|
|
+private:
|
|
|
+ T renderer_;
|
|
|
+ const vector<Name>& names_;
|
|
|
+};
|
|
|
+
|
|
|
+//
|
|
|
+// Builtin benchmark data.
|
|
|
+//
|
|
|
+// This consists of all names contained in a response from a root server for
|
|
|
+// the query for "www.example.com" (as of this implementing).
|
|
|
+const char* const root_to_com_names[] = {
|
|
|
+ // question section
|
|
|
+ "www.example.com",
|
|
|
+ // authority section
|
|
|
+ "com", "a.gtld-servers.net", "com", "b.gtld-servers.net",
|
|
|
+ "com", "c.gtld-servers.net", "com", "d.gtld-servers.net",
|
|
|
+ "com", "e.gtld-servers.net", "com", "f.gtld-servers.net",
|
|
|
+ "com", "g.gtld-servers.net", "com", "h.gtld-servers.net",
|
|
|
+ "com", "i.gtld-servers.net", "com", "j.gtld-servers.net",
|
|
|
+ "com", "k.gtld-servers.net", "com", "l.gtld-servers.net",
|
|
|
+ "com", // owner name of DS
|
|
|
+ "com", // owner name of RRSIG(DS)
|
|
|
+ // additional section. a and b has both AAAA and A; others have A only.
|
|
|
+ "a.gtld-servers.net", "a.gtld-servers.net",
|
|
|
+ "b.gtld-servers.net", "b.gtld-servers.net",
|
|
|
+ "c.gtld-servers.net", "d.gtld-servers.net", "e.gtld-servers.net",
|
|
|
+ "f.gtld-servers.net", "g.gtld-servers.net", "h.gtld-servers.net",
|
|
|
+ "i.gtld-servers.net", "j.gtld-servers.net", "k.gtld-servers.net",
|
|
|
+ "l.gtld-servers.net", "m.gtld-servers.net",
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+// Names contained a typical "NXDOMAIN" response: the question, the owner
|
|
|
+// name of SOA, and its MNAME and RNAME.
|
|
|
+const char* const example_nxdomain_names[] = {
|
|
|
+ "www.example.com", "example.com", "ns.example.com", "root.example.com",
|
|
|
+ NULL
|
|
|
+};
|
|
|
+
|
|
|
+// Names contained a typical "SERVFAIL" response: only the question.
|
|
|
+const char* const example_servfail_names[] = {
|
|
|
+ "www.example.com", NULL
|
|
|
+};
|
|
|
+
|
|
|
+// An experimental "dumb" renderer for comparison. It doesn't do any name
|
|
|
+// compression. It simply ignores all setter method, returns a dummy value
|
|
|
+// for getter methods, and write names to the internal buffer as plain binary
|
|
|
+// data.
|
|
|
+class DumbMessageRenderer : public AbstractMessageRenderer {
|
|
|
+public:
|
|
|
+ virtual void clear() {}
|
|
|
+ virtual size_t getLengthLimit() const { return (512); }
|
|
|
+ virtual void setLengthLimit(const size_t) {}
|
|
|
+ virtual bool isTruncated() const { return (false); }
|
|
|
+ virtual void setTruncated() {}
|
|
|
+ virtual CompressMode getCompressMode() const { return (CASE_INSENSITIVE); }
|
|
|
+ virtual void setCompressMode(const CompressMode) {}
|
|
|
+ virtual void writeName(const Name& name, const bool = false) {
|
|
|
+ name.toWire(getBuffer());
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+void
|
|
|
+usage() {
|
|
|
+ cerr << "Usage: message_renderer_bench [-n iterations]" << endl;
|
|
|
+ exit (1);
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+main(int argc, char* argv[]) {
|
|
|
+ int ch;
|
|
|
+ int iteration = 100000;
|
|
|
+ while ((ch = getopt(argc, argv, "n:")) != -1) {
|
|
|
+ switch (ch) {
|
|
|
+ case 'n':
|
|
|
+ iteration = atoi(optarg);
|
|
|
+ break;
|
|
|
+ case '?':
|
|
|
+ default:
|
|
|
+ usage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ argc -= optind;
|
|
|
+ argv += optind;
|
|
|
+ if (argc != 0) {
|
|
|
+ usage();
|
|
|
+ }
|
|
|
+
|
|
|
+ cout << "Parameters:" << endl;
|
|
|
+ cout << " Iterations: " << iteration << endl;
|
|
|
+
|
|
|
+ typedef pair<const char* const*, string> DataSpec;
|
|
|
+ vector<DataSpec> spec_list;
|
|
|
+ spec_list.push_back(DataSpec(root_to_com_names, "(positive response)"));
|
|
|
+ spec_list.push_back(DataSpec(example_nxdomain_names,
|
|
|
+ "(NXDOMAIN response)"));
|
|
|
+ spec_list.push_back(DataSpec(example_servfail_names,
|
|
|
+ "(SERVFAIL response)"));
|
|
|
+ for (vector<DataSpec>::const_iterator it = spec_list.begin();
|
|
|
+ it != spec_list.end();
|
|
|
+ ++it) {
|
|
|
+ vector<Name> names;
|
|
|
+ for (size_t i = 0; it->first[i] != NULL; ++i) {
|
|
|
+ names.push_back(Name(it->first[i]));
|
|
|
+ }
|
|
|
+
|
|
|
+ typedef MessageRendererBenchMark<OldMessageRenderer>
|
|
|
+ OldRendererBenchMark;
|
|
|
+ cout << "Benchmark for old MessageRenderer " << it->second << endl;
|
|
|
+ BenchMark<OldRendererBenchMark>(iteration,
|
|
|
+ OldRendererBenchMark(names));
|
|
|
+
|
|
|
+ typedef MessageRendererBenchMark<DumbMessageRenderer>
|
|
|
+ DumbRendererBenchMark;
|
|
|
+ cout << "Benchmark for dumb MessageRenderer " << it->second << endl;
|
|
|
+ BenchMark<DumbRendererBenchMark>(iteration,
|
|
|
+ DumbRendererBenchMark(names));
|
|
|
+
|
|
|
+ typedef MessageRendererBenchMark<MessageRenderer> RendererBenchMark;
|
|
|
+ cout << "Benchmark for new MessageRenderer " << it->second << endl;
|
|
|
+ BenchMark<RendererBenchMark>(iteration, RendererBenchMark(names));
|
|
|
+ }
|
|
|
+
|
|
|
+ return (0);
|
|
|
+}
|