summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac2
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/tools/Makefile.am1
-rw-r--r--tests/tools/dhcp-ubench/Makefile65
-rw-r--r--tests/tools/dhcp-ubench/README10
-rw-r--r--tests/tools/dhcp-ubench/benchmark.cc198
-rw-r--r--tests/tools/dhcp-ubench/benchmark.h209
-rw-r--r--tests/tools/dhcp-ubench/dhcp-perf-guide.xml1452
-rw-r--r--tests/tools/dhcp-ubench/memfile_ubench.cc356
-rw-r--r--tests/tools/dhcp-ubench/memfile_ubench.h103
-rw-r--r--tests/tools/dhcp-ubench/mysql.schema86
-rw-r--r--tests/tools/dhcp-ubench/mysql_ubench.cc674
-rw-r--r--tests/tools/dhcp-ubench/mysql_ubench.h104
-rw-r--r--tests/tools/dhcp-ubench/performance-results-graph1.pngbin38873 -> 0 bytes
-rw-r--r--tests/tools/dhcp-ubench/performance-results-graph2.pngbin38979 -> 0 bytes
-rw-r--r--tests/tools/dhcp-ubench/performance-results.odsbin48268 -> 0 bytes
-rw-r--r--tests/tools/dhcp-ubench/sqlite.schema85
-rw-r--r--tests/tools/dhcp-ubench/sqlite_ubench.cc513
-rw-r--r--tests/tools/dhcp-ubench/sqlite_ubench.h74
20 files changed, 1 insertions, 3935 deletions
diff --git a/Makefile.am b/Makefile.am
index f580336779..56fe5dcd49 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4macros ${ACLOCAL_FLAGS}
# ^^^^^^^^ This has to be the first line and cannot come later in this
# Makefile.am due to some bork in some versions of autotools.
-SUBDIRS = compatcheck doc . ext src tests m4macros
+SUBDIRS = compatcheck doc . ext src m4macros
USE_LCOV=@USE_LCOV@
LCOV=@LCOV@
GENHTML=@GENHTML@
@@ -81,7 +81,6 @@ endif
if HAVE_OPENSSL
openssl/\* \
endif
- tests/\* \
unittests/\* \
\*_unittests.cc \
\*_unittest.cc \
diff --git a/configure.ac b/configure.ac
index 65810afe67..8fbcad25e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1504,8 +1504,6 @@ AC_CONFIG_FILES([compatcheck/Makefile
src/lib/util/threads/tests/Makefile
src/lib/util/unittests/Makefile
tools/path_replacer.sh
- tests/Makefile
- tests/tools/Makefile
])
AC_CONFIG_COMMANDS([permissions], [
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index e214ef2523..0000000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = tools \ No newline at end of file
diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am
deleted file mode 100644
index 1a7eb296dc..0000000000
--- a/tests/tools/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-SUBDIRS = .
diff --git a/tests/tools/dhcp-ubench/Makefile b/tests/tools/dhcp-ubench/Makefile
deleted file mode 100644
index 16735e9972..0000000000
--- a/tests/tools/dhcp-ubench/Makefile
+++ /dev/null
@@ -1,65 +0,0 @@
-# Linux switches
-CFLAGS= -Ofast -Wall -pedantic -Wextra
-
-# Mac OS: We don't use pedantic as Mac OS version of MySQL (5.5.24) does use long long (not part of ISO C++)
-#CFLAGS=-g -O0 -Wall -Wextra -I/opt/local/include
-
-# Mac OS does not require -lrt
-# Linux requires -lrt
-LDFLAGS=-lrt
-
-MEMFILE_CFLAGS=
-MEMFILE_LDFLAGS=
-
-# It is mysql_config on most Linux systems and mysql_config5 on Mac OS
-MYSQL_CONFIG=mysql_config
-
-MYSQL_CFLAGS=`$(MYSQL_CONFIG) --cflags`
-MYSQL_LDFLAGS=`$(MYSQL_CONFIG) --libs`
-
-SQLITE_CFLAGS=`pkg-config sqlite3 --cflags`
-SQLITE_LDFLAGS=`pkg-config sqlite3 --libs`
-
-all: mysql_ubench sqlite_ubench memfile_ubench
-
-doc: dhcp-perf-guide.html dhcp-perf-guide.pdf
-
-mysql_ubench.o: mysql_ubench.cc mysql_ubench.h benchmark.h
- $(CXX) $< -c $(CFLAGS) $(MYSQL_CFLAGS)
-
-benchmark.o: benchmark.cc benchmark.h
- $(CXX) $< -c $(CFLAGS) $(MYSQL_CFLAGS)
-
-mysql_ubench: mysql_ubench.o benchmark.o
- $(CXX) $< benchmark.o -o mysql_ubench $(CFLAGS) $(MYSQL_CFLAGS) $(LDFLAGS) $(MYSQL_LDFLAGS)
-
-sqlite_ubench.o: sqlite_ubench.cc sqlite_ubench.h benchmark.h
- $(CXX) $< -c $(CFLAGS) $(SQLLITE_CFLAGS)
-
-sqlite_ubench: sqlite_ubench.o benchmark.o
- $(CXX) $< benchmark.o -o sqlite_ubench $(CFLAGS) $(SQLITE_CFLAGS) $(LDFLAGS) $(SQLITE_LDFLAGS)
-
-memfile_ubench.o: memfile_ubench.cc memfile_ubench.h benchmark.h
- $(CXX) $< -c $(CFLAGS) $(MEMFILE_CFLAGS)
-
-memfile_ubench: memfile_ubench.o benchmark.o
- $(CXX) $< benchmark.o -o memfile_ubench $(LDFLAGS) $(MEMFILE_LDFLAGS)
-
-clean:
- rm -f mysql_ubench sqlite_ubench memfile_ubench *.o
-
-version.ent:
- ln -s ../../../doc/version.ent
-
-dhcp-perf-guide.html: dhcp-perf-guide.xml version.ent
- xsltproc --novalid --xinclude --nonet \
- -o $@ \
- --path ../../../doc \
- --stringparam section.autolabel 1 \
- --stringparam section.label.includes.component.label 1 \
- --stringparam html.stylesheet bind10-guide.css \
- http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl \
- dhcp-perf-guide.xml
-
-dhcp-perf-guide.pdf: dhcp-perf-guide.xml
- dblatex -P doc.collab.show=0 -P latex.output.revhistory=0 $<
diff --git a/tests/tools/dhcp-ubench/README b/tests/tools/dhcp-ubench/README
deleted file mode 100644
index 1bada272e3..0000000000
--- a/tests/tools/dhcp-ubench/README
+++ /dev/null
@@ -1,10 +0,0 @@
-
- This directory contains benchmarks for various planned and considered database
- backends for BIND10 DHCP, codename Kea.
-
- Before using the code, please read DHCP Performance Guide, available in
- HTML and PDF formats.
-
- To compile the code, type: make
-
- To regenerate documentation, type: make doc
diff --git a/tests/tools/dhcp-ubench/benchmark.cc b/tests/tools/dhcp-ubench/benchmark.cc
deleted file mode 100644
index c987bf5013..0000000000
--- a/tests/tools/dhcp-ubench/benchmark.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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 <iostream>
-#include <stdlib.h>
-#include <string.h>
-#include <boost/lexical_cast.hpp>
-#include "benchmark.h"
-
-// The following headers are for getting precise time (clock_gettime on Linux or that mac os thingie)
-#include <time.h>
-#include <sys/time.h>
-#ifdef __MACH__
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
-
-using namespace std;
-
-uBenchmark::uBenchmark(uint32_t iterations, const std::string& dbname,
- bool sync /*= false*/, bool verbose /*= true*/,
- const std::string& host /* = "" */,
- const std::string& user /* = "" */,
- const std::string& pass /* = "" */)
- :num_(iterations), sync_(sync), verbose_(verbose),
- hostname_(host), user_(user), passwd_(pass), dbname_(dbname),
- hitratio_(0.9f), compiled_stmt_(true)
-{
- /// @todo: make compiled statements a configurable parameter
-
- /// @todo: convert hitratio_ to user-configurable parameter
-
- memset(ts_, 0, sizeof(ts_));
-}
-
-void uBenchmark::usage() {
- cout << "This is a benchmark designed to measure expected performance" << endl;
- cout << "of several backends. This backend identifies itself as:" << endl;
- printInfo();
-
- cout << endl << "Possible command-line parameters:" << endl;
- cout << " -h - help (you are reading this)" << endl;
- cout << " -m hostname - specifies MySQL server to connect (MySQL backend only)" << endl;
- cout << " -u username - specifies MySQL user name (MySQL backend only)" << endl;
- cout << " -p password - specifies MySQL passwod (MySQL backend only)" << endl;
- cout << " -f name - database or filename (MySQL, SQLite and memfile)" << endl;
- cout << " -n integer - number of test iterations (MySQL, SQLite and memfile)" << endl;
- cout << " -s yes|no - synchronous/asynchronous operation (MySQL, SQLite and memfile)" << endl;
- cout << " -v yes|no - verbose mode (MySQL, SQLite and memfile)" << endl;
- cout << " -c yes|no - compiled statements (MySQL and SQLite)" << endl;
-
- exit(EXIT_FAILURE);
-}
-
-void uBenchmark::parseCmdline(int argc, char* const argv[]) {
- int ch;
-
- while ((ch = getopt(argc, argv, "hm:u:p:f:n:s:v:c:")) != -1) {
- switch (ch) {
- case 'h':
- usage();
- case 'm':
- hostname_ = string(optarg);
- break;
- case 'u':
- user_ = string(optarg);
- break;
- case 'p':
- passwd_ = string(optarg);
- break;
- case 'f':
- dbname_ = string(optarg);
- break;
- case 'n':
- try {
- num_ = boost::lexical_cast<unsigned int>(optarg);
- } catch (const boost::bad_lexical_cast &) {
- cerr << "Failed to parse number of iterations (-n option):"
- << optarg << endl;
- usage();
- }
- break;
- case 'c':
- compiled_stmt_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
- break;
- case 's':
- sync_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
- break;
- case 'v':
- verbose_ = !strcasecmp(optarg, "yes") || !strcmp(optarg, "1");
- break;
- default:
- usage();
- }
- }
-}
-
-void uBenchmark::failure(const char* operation) {
- cout << "Error during " << operation << endl;
- throw string(operation);
-}
-
-void uBenchmark::printClock(const std::string& operation, uint32_t num,
- const struct timespec& before,
- const struct timespec& after) {
- long int tv_sec = after.tv_sec - before.tv_sec;
-
- long int tv_nsec = after.tv_nsec - before.tv_nsec;
-
- if (tv_nsec < 0) {
- tv_sec--;
- tv_nsec += 1000000000; // 10^9
- }
-
- double oneoper = (tv_nsec/1000 + tv_sec*1000000)/num;
-
- cout << operation << " repeated " << num << " times took "
- << tv_sec << " s, " << tv_nsec/1000 << " us, 1 operation took "
- << oneoper << "us (or " << (1000000/oneoper) << " oper/sec)" << endl;
-
-}
-
-int uBenchmark::run() {
-
- cout << "Starting test. Parameters:" << endl
- << "Number of iterations : " << num_ << endl
- << "Sync/async : " << (sync_ ? "sync" : "async") << endl
- << "Verbose : " << (verbose_ ? "verbose" : "quiet") << endl
- << "Compiled statements : " << (compiled_stmt_ ? "yes": "no") << endl
- << "Database name : " << dbname_ << endl
- << "MySQL hostname : " << hostname_ << endl
- << "MySQL username : " << user_ << endl
- << "MySQL password : " << passwd_ << endl << endl;
-
-
- srandom(time(NULL));
-
- try {
- connect();
-
- ts_[0] = getTime();
-
- createLease4Test();
- ts_[1] = getTime();
-
- searchLease4Test();
- ts_[2] = getTime();
-
- updateLease4Test();
- ts_[3] = getTime();
-
- deleteLease4Test();
- ts_[4] = getTime();
-
- disconnect();
-
- } catch (const std::string& e) {
- cout << "Failed: " << e << endl;
- return (-1);
- }
-
- printClock("Create leases4", num_, ts_[0], ts_[1]);
- printClock("Search leases4", num_, ts_[1], ts_[2]);
- printClock("Update leases4", num_, ts_[2], ts_[3]);
- printClock("Delete leases4", num_, ts_[3], ts_[4]);
-
- return (0);
-}
-
-struct timespec uBenchmark::getTime() {
- struct timespec ts;
-
-#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
- clock_serv_t cclock;
- mach_timespec_t mts;
- host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
- clock_get_time(cclock, &mts);
- mach_port_deallocate(mach_task_self(), cclock);
- ts.tv_sec = mts.tv_sec;
- ts.tv_nsec = mts.tv_nsec;
-#else
- clock_gettime(CLOCK_REALTIME, &ts);
-#endif
-
- return ts;
-}
diff --git a/tests/tools/dhcp-ubench/benchmark.h b/tests/tools/dhcp-ubench/benchmark.h
deleted file mode 100644
index fc3360698c..0000000000
--- a/tests/tools/dhcp-ubench/benchmark.h
+++ /dev/null
@@ -1,209 +0,0 @@
-// 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 <string>
-#include <stdint.h>
-
-#ifndef BENCHMARK_H
-#define BENCHMARK_H
-
-/// @brief Micro-benchmark base class.
-///
-/// This class represents an abstract DHCP database backend benchmark.
-/// It is not intended to be used directly, but serves as a common
-/// denominator for specific backend benchmarks that are derived from
-/// it. Currently there are at least 3 benchmarks implemented that
-/// take advantage of it:
-/// - MySQL (MySQL_uBenchmark)
-/// - SQLite (SQLite_uBenchmark)
-/// - memfile (memfile_uBenchmark)
-class uBenchmark {
-public:
-
- /// @brief the sole constructor, used by all derivated benchmarks
- ///
- /// @param iterations number of iterations of each step (insert, search,
- /// update, delete)
- /// @param dbname name of the database (that is backend-specific, either
- /// filename or DB name)
- /// @param sync sync or async test mode
- /// @param verbose should extra logging be enabled?
- /// @param host some backends (currently only MySQL) need this (optional)
- /// @param username some backends (currently only MySQL) need this (optional)
- /// @param pass some backends (currently only MySQL) need this (optional)
- uBenchmark(uint32_t iterations, const std::string& dbname,
- bool sync, bool verbose,
- const std::string& host = "",
- const std::string& username = "",
- const std::string& pass = "");
-
- /// @brief Prints version information about specific backend.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void printInfo() = 0;
-
- /// @brief Opens a connection to the database.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void connect() = 0;
-
- /// @brief Closes connection to the database.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void disconnect() = 0;
-
- /// @brief Benchmarks IPv4 address lease creation.
- ///
- /// That benchmark method will be called first.
- /// It is expected to create specific number of leases,
- /// as specified by \ref num_ parameter. Following
- /// methods (searchLease4Test(), updateLease4Test(),
- /// and deleteLease4Test()) assume that lease creation
- /// is successful. The benchmark is expected to create leases
- /// starting from BASE_ADDR4 and ending on BASE_ADDR4 + num_.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void createLease4Test() = 0;
-
- /// @brief Benchmarks IPv4 address lease search.
- ///
- /// This is the second benchmark in a series of four.
- /// It is called after createLease4Test(), so it expects that the
- /// database is populated with at least \ref num_ leases.
- /// It repeats search for a lease num_ times.
- ///
- /// The algorithm randomly picks a lease with \ref hitratio_ (typically 90%)
- /// chance of finding a lease. During typical DHCP operation the server
- /// sometimes wants to check if specific lease is assigned or not and the
- /// lease is sometimes not present (e.g. when randomly trying to pick a new
- /// lease for a new client or doing confirm). Although rather unlikely,
- /// cases when searching for non-existing leases may be more costly,
- /// thus should be modelled.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void searchLease4Test() = 0;
-
- /// @brief Benchmarks IPv4 address lease update.
- ///
- /// This is the third benchmark in a series of four.
- /// It is called after createLease4Test(), so it expects that the
- /// database is populated with at least \ref num_ leases.
- ///
- /// In a normal DHCP operation, search and update operations are used
- /// together, but for the benchmarking purposes they are executed
- /// separately here. Once a lease is found, it is being updated. Typically
- /// the update is just changing lease expiration timers, so that is what
- /// the test does. It exploits the fact that there are num_ leases
- /// in the database, so it picks randomly an address from
- /// BASE_ADDR4 ... BASE_ADDR4 + num_ range and has a guarantee for the lease
- /// to be present.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void updateLease4Test() = 0;
-
- /// @brief Benchmarks IPv4 address lease removal.
- ///
- /// This is the last benchmark in a series of four.
- /// It is called after createLease4Test(), so it expects that the
- /// database is populated with at least \ref num_ leases.
- ///
- /// It is expected to iteratively delete all num_ leases from
- /// the database.
- ///
- /// The implementation is provided by the DB-specific class.
- virtual void deleteLease4Test() = 0;
-
- /// @brief Utility function for reporting errors.
- ///
- /// Benchmarks should call that function when something goes wrong.
- /// details of the problem must be passed as a parameter. As the benchmark
- /// is not designed to recover from errors, reporting an error aborts
- /// benchmark execution.
- ///
- /// @param operation description of the operation that caused failure
- virtual void failure(const char* operation);
-
- /// @brief Prints elapsed time of a specific operation
- ///
- /// This method prints out elapsed time of a specific benchmark, together
- /// with additional statistics.
- ///
- /// @param operation name of the operation (usually create, search, update, delete)
- /// @param num number or iterations (used for statistics)
- /// @param before timestamp before execution
- /// @param after timestamp after execution
- void printClock(const std::string& operation, uint32_t num,
- const struct timespec& before,
- const struct timespec& after);
-
- /// @brief Main benchmark execution routine
- ///
- /// This method calls create, search, update and delete benchmarks
- /// and measures appropriate timestamps in ts_ table.
- ///
- /// @return 0 if the run was successful, negative value if detected errors
- int run();
-
- /// @brief parses command-line parameters
- ///
- /// This method parses command-line parameters and sets up appropriate
- /// values. It is ok to pass argc, argv from main() here.
- ///
- /// This method may not return if -h (help) was specified or invalid
- /// arguments are passed. Appropriate error and help will be displayed
- /// and the program will terminate.
- ///
- /// @param argc number of arguments
- /// @param argv array to the arguments
- void parseCmdline(int argc, char* const argv[]);
-
-protected:
- /// @brief prints out command-line help (list of parameters + version)
- void usage();
-
- /// @brief a wrapper around OS-specific method for getting time
- struct timespec getTime();
-
- /// Number of operations (e.g. insert lease num times)
- uint32_t num_;
-
- /// Synchronous or asynchronous mode?
- bool sync_;
-
- /// Should the test print out extra information?
- bool verbose_;
-
- // DB parameters
- std::string hostname_; // used by MySQL only
- std::string user_; // used by MySQL only
- std::string passwd_; // used by MySQL only
- std::string dbname_; // used by MySQL, SQLite and memfile
-
- /// @brief hit ratio for search test (must be between 0.0 and 1.0)
- ///
- /// This parameter is used in search benchmark. The formula causes the
- /// search to find something a lease in 90% cases of hit ratio is 0.9.
- float hitratio_;
-
- /// benchmarks must generate the leases starting from 1.0.0.0 address
- const static uint32_t BASE_ADDR4 = 0x01000000;
-
- /// five timestamps (1 at the beginning and 4 after each step)
- struct timespec ts_[5];
-
- /// should compiled statements be used?
- bool compiled_stmt_;
-};
-
-#endif
diff --git a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml b/tests/tools/dhcp-ubench/dhcp-perf-guide.xml
deleted file mode 100644
index 0115cd60cd..0000000000
--- a/tests/tools/dhcp-ubench/dhcp-perf-guide.xml
+++ /dev/null
@@ -1,1452 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
-<!ENTITY mdash "&#x2014;" >
-<!ENTITY % version SYSTEM "version.ent">
-%version;
-]>
-
-<!--
- - 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.
--->
-
-<?xml-stylesheet href="bind10-guide.css" type="text/css"?>
-
-<book>
- <bookinfo>
- <title>DHCP Performance Guide</title>
- <!-- <subtitle>Various aspects of DHCP Performance in BIND 10</subtitle> -->
-
- <copyright>
- <year>2012</year>
- <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
- </copyright>
- <author>
- <firstname>Tomasz</firstname>
- <surname>Mrugalski</surname>
- </author>
- <author>
- <firstname>Marcin</firstname>
- <surname>Siodelski</surname>
- </author>
- <abstract>
- <para>BIND 10 is a framework that features Domain Name System
- (DNS) and Dynamic Host Configuration Protocol (DHCP)
- software with development managed by Internet Systems Consortium (ISC).
- This document describes various aspects of DHCP performance,
- measurements and tuning. It covers BIND 10 DHCP (codename Kea),
- existing ISC DHCP4 software, perfdhcp (a DHCP performance
- measurement tool) and other related topics.</para>
- </abstract>
-
- <releaseinfo>This is a companion document for BIND 10 version
- &__VERSION__;.</releaseinfo>
-
- </bookinfo>
-
- <preface>
- <title>Preface</title>
-
- <section id="acknowledgements">
- <title>Acknowledgements</title>
-
- <para>ISC would like to acknowledge generous support for
- BIND 10 development of DHCPv4 and DHCPv6 components provided
- by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
-
- </section>
-
- </preface>
-
- <chapter id="intro">
- <title>Introduction</title>
- <para>
- This document is in the early stages of development. It is
- expected to grow significantly in the near future. It will
- cover topics like database backend perfomance measurements,
- tools, and the pros an cons of various optimization techniques.
- </para>
-
- </chapter>
-
- <chapter id="dhcp4">
- <title>ISC DHCP 4.x</title>
- <para>
- TODO: Write something about ISC DHCP4 here.
- </para>
- </chapter>
-
- <chapter id="kea">
- <title>Kea</title>
- <para>
-
- </para>
-
- <section>
- <title>Backend performance evaluation</title>
- <para>
- Kea will support several different database backends, using
- both popular databases (like MySQL or SQLite) and
- custom-developed solutions (such as an in-memory database).
- To aid in the choice of backend, the BIND 10
- source code features a set of performance microbenchmarks.
- Written in C/C++, these are small tools that simulate expected
- DHCP server behaviour and evaluate the performance of
- considered databases. As implemented, the benchmarks are not really
- simulating DHCP operation, but rather use set of primitives
- that can be used by a real server. For this reason, they are called
- micro-benchmarks.
- </para>
-
- <para>Although there are many operations and data types that
- server could store in a database, the most frequently used data
- type is lease information. Although the information held for IPv4
- and IPv6 leases differs slightly, it is expected that the performance
- differences will be minimal between IPv4 and IPv6 lease operations.
- Therefore each test uses the lease4 table (in which IPv4 leases are stored)
- for performance measurements.
- </para>
-
- <para>All benchmarks are implemented as single threaded applications
- that take advantage of a single database connection.</para>
-
- <para>
- Those benchmarks are stored in tests/tools/dhcp-ubench directory of the
- BIND 10 source tree. This directory contains simplified prototypes for
- the various database back-ends that are planned or considered as a
- possibly for BIND10 DHCP. These benchmarks are expected to evolve into
- useful tools that will allow users to measure performance in their
- specific environment.
- </para>
-
- <para>
- Currently the following benchmarks are implemented:
- <itemizedlist>
- <listitem><para>In memory + flat file</para></listitem>
- <listitem><para>SQLite</para></listitem>
- <listitem><para>MySQL</para></listitem>
- </itemizedlist>
- </para>
-
- <para>
- As the benchmarks require additional (sometimes heavy) dependencies, they
- are not built by default. Actually, their build system is completely
- separate from that of the rest of BIND 10. It will be eventually merged
- with the main BIND 10 build system.
- </para>
-
- <para>
- All benchmarks will follow the same pattern:
- <orderedlist>
- <listitem><para>Prepare operation (connect to a database, create a file etc.)</para></listitem>
- <listitem><para>Measure timestamp 0</para></listitem>
- <listitem><para>Commit new lease4 record (repeated N times)</para></listitem>
- <listitem><para>Measure timestamp 1</para></listitem>
- <listitem><para>Search for random lease4 record (repeated N times)</para></listitem>
- <listitem><para>Measure timestamp 2</para></listitem>
- <listitem><para>Update existing lease4 record (repeated N times)</para></listitem>
- <listitem><para>Measure timestamp 3</para></listitem>
- <listitem><para>Delete existing lease4 record (repeated N times)</para></listitem>
- <listitem><para>Measure timestamp 4</para></listitem>
- <listitem><para>Print out statistics, based on N and measured timestamps.</para></listitem>
- </orderedlist>
-
- Although this approach does not attempt to simulate actual DHCP server
- operation that has mix of all steps, it answers the
- questions about basic database strengths and weak points. In particular
- it can show what is the impact of specific database optimizations, such as
- changing engine, optimizing for writes/reads etc.
- </para>
-
- <para>
- The framework attempts to do the same amount of work for every
- backend thus allowing fair comparison between them.
- </para>
- </section>
-
- <section id="mysql-backend">
- <title>MySQL backend</title>
- <para>The MySQL backend requires the MySQL client development libraries. It uses
- the mysql_config tool (similar to pkg-config) to discover required
- compilation and linking options. To install required packages on Ubuntu,
- use the following command:
-
- <screen>$ <userinput>sudo apt-get install mysql-client mysql-server libmysqlclient-dev</userinput></screen>
-
- Make sure that MySQL server is running. Make sure that you have your setup
- configured so there is a user that is able to modify used database.</para>
-
- <para>Before running tests, you need to initialize your database. You can
- use mysql.schema script for that purpose.</para>
-
- <para><emphasis>WARNING: It will drop existing
- Kea database. Do not run this on your production server. </emphasis></para>
-
- <para>Assuming your
- MySQL user is "kea", you can initialize your test database by:
-
- <screen>$ <userinput>mysql -u kea -p &lt; mysql.schema</userinput></screen>
- </para>
-
- <para>After the database is initialized, you are ready to run the test:
- <screen>$ <userinput>./mysql_ubench</userinput></screen>
-
- or
-
- <screen>$ <userinput>./mysql_ubench &gt; results-mysql.txt</userinput></screen>
-
- Redirecting output to a file is important, because for each operation
- there is a single character printed to show progress. If you have a slow
- terminal, this may considerably affect test performance. On the other hand,
- printing something after each operation is required as poor database settings
- may slow down operations to around 20 per second. (The observant user is expected
- to note that the initial dots are printed too slowly and abort the test.)</para>
-
- <para>Currently all default parameters are hardcoded. Default values can be
- overridden using command line switches. Although all benchmarks take
- the same list of parameters, some of them are specific to a given backend.
- To get a list of supported parameters, run the benchmark with the "-h" option:
-
- <screen>$ <userinput>./mysql_ubench -h</userinput></screen>
- </para>
-
- <para>Synchronous operation requires database backend to
- physically store changes to disk before proceeding. This
- property ensures that no data is lost in case of the server
- failure. Unfortunately, it slows operation
- considerably. Asynchronous mode allows database to write data at
- a later time (usually controlled by the database engine on OS
- disk buffering mechanism).</para>
-
- <section>
- <title>MySQL tweaks</title>
-
- <para>To modify the default mysql_ubench parameters, command line
- switches can be used. The currently supported switches are
- (default values specified in brackets):
- <orderedlist>
- <listitem><para>-f name - name of the database ("kea")</para></listitem>
- <listitem><para>-m hostname - name of the database host ("localhost")</para></listitem>
- <listitem><para>-u user - MySQL username ("root")</para></listitem>
- <listitem><para>-p password - MySQL password ("secret")</para></listitem>
- <listitem><para>-n num - number of iterations (100)</para></listitem>
- <listitem><para>-s yes|no - should the operations be performed in a synchronous (yes)
- or asynchronous (no) manner (yes)</para></listitem>
- <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
- <listitem><para>-c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes)</para></listitem>
- </orderedlist>
- </para>
-
-
- <para>One parameter that has huge impact on performance is the choice of backend engine.
- You can get a list of engines of your MySQL implementation by using
-
- <screen>&gt; <userinput>show engines;</userinput></screen>
-
- in your mysql client. Two notable engines are MyISAM and InnoDB. mysql_ubench uses
- use MyISAM for synchronous mode and InnoDB for asynchronous. Please use
- '-s yes|no' to choose whether you want synchronous or asynchronous operations.</para>
-
- <para>Another parameter that affects performance are precompiled statements.
- In a basic approach, the actual SQL query is passed as a text string that is
- then parsed by the database engine. Alternative is a so called precompiled
- statement. In this approach the SQL query is compiled an specific values are being
- bound to it. In the next iteration the query remains the same, only bound values
- are changing (e.g. searching for a different address). Usage of basic or precompiled
- statements is controlled with '-c no|yes'.</para>
- </section>
- </section>
-
-
- <section id="sqlite-ubench">
- <title>SQLite-ubench</title>
- <para>The SQLite backend requires both the sqlite3 development and run-time packages. Their
- names may vary from system to system, but on Ubuntu 12.04 they are called
- sqlite3 libsqlite3-dev. To install them, use the following command:
-
- <screen>&gt; <userinput>sudo apt-get install sqlite3 libsqlite3-dev</userinput></screen>
-
- Before running the test the database has to be created. Use the following command for that:
- <screen>&gt; <userinput>cat sqlite.schema | sqlite3 sqlite.db</userinput></screen>
-
- A new database called sqlite.db will be created. That is the default name used
- by sqlite_ubench test. If you prefer other name, make sure you update
- sqlite_ubench.cc accordingly.</para>
-
- <para>Once the database is created, you can run tests:
- <screen>&gt; <userinput>./sqlite_ubench</userinput></screen>
- or
- <screen>&gt; <userinput>./sqlite_ubench > results-sqlite.txt</userinput></screen>
- </para>
-
- <section id="sqlite-tweaks">
- <title>SQLite tweaks</title>
- <para>To modify default sqlite_ubench parameters, command line
- switches can be used. The currently supported switches are
- (default values specified in brackets):
- <orderedlist>
- <listitem><para>-f filename - name of the database file ("sqlite.db")</para></listitem>
- <listitem><para>-n num - number of iterations (100)</para></listitem>
- <listitem><para>-s yes|no - should the operations be performed in a synchronous (yes)
- or asynchronous (no) manner (yes)</para></listitem>
- <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
- <listitem><para>-c yes|no - precompiled statements. Should the SQL statements be precompiled? (yes)</para></listitem>
- </orderedlist>
- </para>
-
- <para>SQLite can run in asynchronous or synchronous mode. This
- mode can be controlled by using "synchronous" parameter. It is set
- using the SQLite command:</para>
-
- <para><command>PRAGMA synchronous = ON|OFF</command></para>
-
- <para>Another tweakable feature is journal mode. It can be
- turned to several modes of operation. Its value can be
- modified in SQLite_uBenchmark::connect(). See
- http://www.sqlite.org/pragma.html#pragma_journal_mode for
- a detailed explanation.</para>
-
- <para>sqlite_bench supports precompiled statements. Please use
- '-c no|yes' to define which should be used: basic SQL query (no) or
- precompiled statement (yes).</para>
- </section>
- </section>
-
- <section id="memfile-ubench">
- <title>memfile-ubench</title> <para>The memfile backend is a
- custom backend that somewhat mimics operation of ISC DHCP4. It
- implements in-memory storage using standard C++ and boost
- mechanisms (std::map and boost::shared_ptr&lt;&gt;). All
- database changes are also written to a lease file, which is
- strictly write-only. This approach takes advantage of the fact
- that file append operation is faster than modifications introduced
- in the middle of the file (as it often requires moving all data
- after modified point, effectively requiring writing large parts of
- the whole file, not just changed fragment).</para>
-
- <para>There are no preparatory steps required for memfile benchmark.
- The only requirement is the ability to create and write specified lease
- file (dhcpd.leases in the current directory). The tests can be run
- as follows:
- <screen>&gt; <userinput>./memfile_ubench</userinput></screen>
- or
- <screen>&gt; <userinput>./memfile_ubench > results-memfile.txt</userinput></screen>
- </para>
-
- <section id="memfile-tweaks">
- <title>memfile tweaks</title>
- <para>To modify default memfile_ubench parameters, command line
- switches can be used. Currently supported switches are
- (default values specified in brackets):
- <orderedlist>
- <listitem><para>-f filename - name of the database file ("dhcpd.leases")</para></listitem>
- <listitem><para>-n num - number of iterations (100)</para></listitem>
- <listitem><para>-s yes|no - should the operations be performend in a synchronous (yes)
- or asynchronous (no) manner (yes)</para></listitem>
- <listitem><para>-v yes|no - verbose mode. Should the test print out progress? (yes)</para></listitem>
- </orderedlist>
- </para>
-
- <para>memfile can run in asynchronous or synchronous mode. This
- mode can be controlled by using sync parameter. It uses
- fflush() and fsync() in synchronous mode to make sure that
- data is not buffered and physically stored on disk.</para>
- </section>
- </section>
-
- <section>
- <title>Basic performance measurements</title>
- <para>This section contains sample results for backend performance measurements,
- taken using microbenchmarks. Tests were conducted on reasonably powerful machine:
- <screen>
-CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
-HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
-OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
-compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
-MySQL version: 5.5.24
-SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e</screen>
- </para>
-
- <para>The benchmarks were run without using precompiled statements.
- The code was compiled with the -O0 flag (no code optimizations).
- Each run was executed once.</para>
-
- <para>Two series of measures were made, synchronous and
- asynchronous. As those modes offer radically different
- performances, synchronous mode was conducted for one
- thousand repetitions and asynchronous mode was conducted for
- one hundred thousand repetitions.</para>
-
- <!-- raw results sync -->
- <table><title>Synchronous results (basic)</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Num' />
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Operations</entry>
- <entry>Create [s]</entry>
- <entry>Search [s]</entry>
- <entry>Update [s]</entry>
- <entry>Delete [s]</entry>
- <entry>Average [s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL</entry>
- <entry>1,000</entry>
- <entry>31.604</entry>
- <entry> 0.117</entry>
- <entry>27.964</entry>
- <entry>27.695</entry>
- <entry>21.845</entry>
- </row>
-
- <row>
- <entry>SQLite</entry>
- <entry>1,000</entry>
- <entry>61.421</entry>
- <entry> 0.033</entry>
- <entry>59.477</entry>
- <entry>56.034</entry>
- <entry>44.241</entry>
- </row>
-
- <row>
- <entry>memfile</entry>
- <entry>1,000</entry>
- <entry>38.224</entry>
- <entry> 0.001</entry>
- <entry>38.041</entry>
- <entry>38.017</entry>
- <entry>28.571</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <para>The following parameters were measured for asynchronous mode.
- MySQL and SQLite were run with one hundred thousand repetitions.</para>
-
- <!-- raw results async -->
- <table><title>Asynchronous results (basic)</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Num' />
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Operations</entry>
- <entry>Create [s]</entry>
- <entry>Search [s]</entry>
- <entry>Update [s]</entry>
- <entry>Delete [s]</entry>
- <entry>Average [s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL</entry>
- <entry>100,000</entry>
- <entry>10.585</entry>
- <entry>10.386</entry>
- <entry>10.062</entry>
- <entry> 8.890</entry>
- <entry> 9.981</entry>
- </row>
-
- <row>
- <entry>SQLite</entry>
- <entry>100,000</entry>
- <entry> 3.710</entry>
- <entry> 3.159</entry>
- <entry> 2.865</entry>
- <entry> 2.439</entry>
- <entry> 3.044</entry>
- </row>
-
- <row>
- <entry>memfile</entry>
- <entry>100,000</entry>
- <entry> 1.300</entry>
- <entry> 0.039</entry>
- <entry> 1.307</entry>
- <entry> 1.278</entry>
- <entry> 0.981</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <para>The presented performance results can be converted into operations per second metrics.
- It should be noted that due to large differences between various operations (sometimes
- over three orders of magnitude), it is difficult to create a simple, readable chart with
- that data.</para>
-
- <table id="tbl-basic-perf-results"><title>Estimated basic performance</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Create [oper/s]</entry>
- <entry>Search [oper/s]</entry>
- <entry>Update [oper/s]</entry>
- <entry>Delete [oper/s]</entry>
- <entry>Average [oper/s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL (async)</entry>
- <entry>9447.47</entry>
- <entry>9627.97</entry>
- <entry>9938.00</entry>
- <entry>11248.34</entry>
- <entry>10065.45</entry>
- </row>
-
- <row>
- <entry>SQLite (async)</entry>
- <entry>26951.59</entry>
- <entry>31654.29</entry>
- <entry>34899.70</entry>
- <entry>40993.59</entry>
- <entry>33624.79</entry>
- </row>
-
- <row>
- <entry>memfile (async)</entry>
- <entry>76944.27</entry>
- <entry>2542588.35</entry>
- <entry>76504.54</entry>
- <entry>78269.25</entry>
- <entry>693576.60</entry>
- </row>
-
-
- <row>
- <entry>MySQL (sync)</entry>
- <entry>31.64</entry>
- <entry>8575.45</entry>
- <entry>35.76</entry>
- <entry>36.11</entry>
- <entry>2169.74</entry>
- </row>
-
- <row>
- <entry>SQLite (sync)</entry>
- <entry>16.28</entry>
- <entry>20045.37</entry>
- <entry>16.81</entry>
- <entry>17.85</entry>
- <entry>7524.08</entry>
- </row>
-
- <row>
- <entry>memfile (sync)</entry>
- <entry>26.16</entry>
- <entry>1223990.21</entry>
- <entry>26.29</entry>
- <entry>26.30</entry>
- <entry>306017.24</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <!-- that is obsolete approach that is going to be removed in docbook 5.0.
- Its only advantage is that it actually works with docbook2pdf -->
- <!--
- <figure>
- <title>Graphical representation of the basic performance
- results presented in table <xref linkend="tbl-basic-perf-results" />.</title>
- <graphic scale="100" fileref="performance-results-graph1.png" />
- </figure>-->
-
- <!-- this works great for HTML export, but is silently ignored by docbook2pdf
- and docbook2ps tools. -->
- <mediaobject>
- <imageobject>
- <imagedata fileref="performance-results-graph1.png" format="PNG" />
- </imageobject>
- <caption>
- <para>Graphical representation of the basic performance results
- presented in table <xref linkend="tbl-basic-perf-results" />.</para>
- </caption>
- </mediaobject>
-
- </section>
-
- <section>
- <title>Optimized performance measurements</title>
- <para>This section contains sample results for backend performance measurements,
- taken using microbenchmarks. Tests were conducted on reasonably powerful machine:
- <screen>
-CPU: Quad-core Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz (8 logical cores)
-HDD: 1,5TB Seagate Barracuda ST31500341AS 7200rpm, ext4 partition
-OS: Ubuntu 12.04, running kernel 3.2.0-26-generic SMP x86_64
-compiler: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
-MySQL version: 5.5.24
-SQLite version: 3.7.9sourceid version is 2011-11-01 00:52:41 c7c6050ef060877ebe77b41d959e9df13f8c9b5e</screen>
- </para>
-
- <para>The benchmarks were run with precompiled statements enabled.
- The code was compiled with the -Ofast flag (optimize compilation for speed).
- Each run was repeated three times and measured values were averaged.</para>
-
- <para>Again the benchmarks were run in two series, synchronous and
- asynchronous. As those modes offer radically different
- performances, synchronous mode was conducted for one
- thousand repetitions and asynchronous mode was conducted for
- one hundred thousand repetitions.</para>
-
- <!-- raw results sync -->
- <table><title>Synchronous results (optimized)</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Num' />
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Operations</entry>
- <entry>Create [s]</entry>
- <entry>Search [s]</entry>
- <entry>Update [s]</entry>
- <entry>Delete [s]</entry>
- <entry>Average [s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL</entry>
- <entry>1,000</entry>
- <entry>27.887</entry>
- <entry> 0.106</entry>
- <entry>28.223</entry>
- <entry>27.696</entry>
- <entry>20.978</entry>
- </row>
-
- <row>
- <entry>SQLite</entry>
- <entry>1,000</entry>
- <entry>61.299</entry>
- <entry> 0.015</entry>
- <entry>59.648</entry>
- <entry>61.098</entry>
- <entry>45.626</entry>
- </row>
-
- <row>
- <entry>memfile</entry>
- <entry>1,000</entry>
- <entry>39.564</entry>
- <entry> 0.001</entry>
- <entry>39.543</entry>
- <entry>39.326</entry>
- <entry>29.608</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <para>The following parameters were measured for asynchronous mode.
- MySQL and SQLite were run with one hundred thousand repetitions.</para>
-
- <!-- raw results async -->
- <table><title>Asynchronous results (optimized)</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Num' />
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Operations</entry>
- <entry>Create [s]</entry>
- <entry>Search [s]</entry>
- <entry>Update [s]</entry>
- <entry>Delete [s]</entry>
- <entry>Average [s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL</entry>
- <entry>100,000</entry>
- <entry>8.507</entry>
- <entry>9.698</entry>
- <entry>7.785</entry>
- <entry>8.326</entry>
- <entry>8.579</entry>
- </row>
-
- <row>
- <entry>SQLite</entry>
- <entry>100,000</entry>
- <entry> 1.562</entry>
- <entry> 0.949</entry>
- <entry> 1.513</entry>
- <entry> 1.502</entry>
- <entry> 1.382</entry>
- </row>
-
- <row>
- <entry>memfile</entry>
- <entry>100,000</entry>
- <entry>1.302</entry>
- <entry>0.038</entry>
- <entry>1.306</entry>
- <entry>1.263</entry>
- <entry>0.977</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <para>The presented performance results can be converted into operations per second metrics.
- It should be noted that due to large differences between various operations (sometime
- over three orders of magnitude), it is difficult to create a simple, readable chart with
- the data.</para>
-
- <table id="tbl-optim-perf-results"><title>Estimated optimized performance</title>
- <tgroup cols='6' align='center' colsep='1' rowsep='1'>
- <colspec colname='Backend'/>
- <colspec colname='Create'/>
- <colspec colname='Search'/>
- <colspec colname='Update'/>
- <colspec colname='Delete'/>
- <colspec colname='Average'/>
- <thead>
- <row>
- <entry>Backend</entry>
- <entry>Create [oper/s]</entry>
- <entry>Search [oper/s]</entry>
- <entry>Update [oper/s]</entry>
- <entry>Delete [oper/s]</entry>
- <entry>Average [oper/s]</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>MySQL (async)</entry>
- <entry>11754.84</entry>
- <entry>10311.34</entry>
- <entry>12845.35</entry>
- <entry>12010.24</entry>
- <entry>11730.44</entry>
- </row>
-
- <row>
- <entry>SQLite (async)</entry>
- <entry>64005.90</entry>
- <entry>105391.29</entry>
- <entry>66075.51</entry>
- <entry>66566.43</entry>
- <entry>75509.78</entry>
- </row>
-
- <row>
- <entry>memfile (async)</entry>
- <entry>76832.16</entry>
- <entry>2636018.56</entry>
- <entry>76542.50</entry>
- <entry>79188.81</entry>
- <entry>717145.51</entry>
- </row>
-
-
- <row>
- <entry>MySQL (sync)</entry>
- <entry>35.86</entry>
- <entry>9461.10</entry>
- <entry>35.43</entry>
- <entry>36.11</entry>
- <entry>2392.12</entry>
- </row>
-
- <row>
- <entry>SQLite (sync)</entry>
- <entry>16.31</entry>
- <entry>67036.11</entry>
- <entry>16.76</entry>
- <entry>16.37</entry>
- <entry>16771.39</entry>
- </row>
-
- <row>
- <entry>memfile (sync)</entry>
- <entry>25.28</entry>
- <entry>3460207.61</entry>
- <entry>25.29</entry>
- <entry>25.43</entry>
- <entry>865070.90</entry>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <mediaobject>
- <imageobject>
- <imagedata fileref="performance-results-graph2.png" format="PNG"/>
- </imageobject>
- <textobject>
- <phrase>Optimized performance measurements</phrase>
- </textobject>
- <caption>
- <para>Graphical representation of the optimized performance
- results presented in table <xref linkend="tbl-optim-perf-results"
- />.</para>
- </caption>
- </mediaobject>
-
- </section>
-
- <section>
- <title>Conclusions</title>
- <para>
- Improvements gained by introducing support for precompiled
- statements in MySQL is somewhat disappointing - between 6 and
- 29%. On the other hand, the improvement in SQLite is
- surprisingly high - the efficiency is more than doubled.
- </para>
- <para>
- Compiled statements do not have any measureable impact on
- synchronous operations. That is as expected, because the major
- bottleneck is the disk performance.
- </para>
- <para>
- Compilation flags yield surprisingly high improvements for C++
- STL code. The memfile backend is in some operations is almost
- twice as fast.
- </para>
-
- <para>
- If synchronous operation is required, the current performance
- results are likely to be deemed inadequate. The limiting
- factor here is a disk access time. Even migrating to high
- performance 15,000 rpm disk is expected to only roughly double
- number of leases per second, compared to the current results.
- The reason is that to write a file to disk, at least two disk
- sector writes
- are required: the new content and i-node modification of the
- file. The easiest way to boost synchronous performance is to
- switch to SSD disks. Memory-backed RAM disks are also a viable
- solution. However, care should be taken to properly engineer
- backup strategy for such RAM disks.
- </para>
-
- <para>
- While the custom made backend (memfile) provides the best
- perfomance, it carries over all the limitations existing in
- the ISC DHCP4 code: there are no external tools to query or
- change database, the maintenance requires deep knowledge etc.
- Those flaws are not shared by usage of a proper database
- backend, like MySQL and SQLite. They both offer third party
- tools for administrative tasks, they are well documented and
- maintained. However, SQLite support for concurrent access is
- limiting in certain cases. Since all three investigated
- backends more than meet expected performance results, it is
- recommended to use MySQL as a first concrete database backend.
- Should this choice be rejected for any reason, the second
- recommended choice is SQLite.
- </para>
-
- <para>
- It should be emphasized that obtained measurements indicate
- only database performance and they cannot be directly
- translated to expected leases per second or queries per second
- performance by an actual server. The DHCP server must do much
- more than just query the database to properly process client's
- message. The provided results should be considered as only rough
- estimates. They can also be used for relative comparisons
- between backends.
- </para>
-
- </section>
-
- <section>
- <title>Possible further optimizations</title>
- <para>
- For basic measurements the code was compiled with -g -O0
- flags. For optimized measurements the benchmarking code was
- compiled with -Ofast (optimize for speed). In both cases, the
- same backend (MySQL or SQLite) library was used. It may be
- useful to recompile the libraries (or the whole server in case
- of MySQL) with -Ofast.
- </para>
- <para>
- There are many MySQL parameters that various sources recommend
- to improve performance. They were not investigated further.
- </para>
- <para>
- Currently all operations are conducted on one by one
- basis. Each operation is treated as a separate
- transaction. Grouping N operations together will potentially
- bring almost N fold increase in synchronous operations. Such a
- feature is present in ISC DHCP4 and is called cache-threshold.
- Extension for this benchmark in this regard should be
- considered. That affects only write operations (insert,
- update and delete). Read operations (search) are expected to
- be barely affected.
- </para>
- <para>
- Multi-threaded or multi-process benchmark may be considered in
- the future. It may be somewhat difficult as only some backends
- support concurrent access.
- </para>
- </section>
-
- </chapter>
-
- <chapter id="perfdhcp">
- <title>perfdhcp</title>
- <section>
- <title>Purpose</title>
- <para>
- Evaluation of the performance of a DHCP server requires that it
- be tested under varying traffic loads. perfdhcp is a testing
- tool with the capability to create traffic loads
- and generate statistics from the results. Additional features,
- such as the ability to send customised DHCP packets, allow it to
- be used in a wide range of functional testing.
- </para>
- </section>
- <section id="perfdhcp-key-features">
- <title>Key features</title>
- <para>
- perfdhcp has a number of command line switches to
- control DHCP message exchanges. Currently they fall into
- the following categories:
- <itemizedlist>
- <listitem>
- <para>
- Rate control - control how many DHCP exchanges
- are initiated within a period of time. The tool can also simulate
- best effort conditions by attempting to initiate as many DHCP
- packet exchanges as possible within a unit of time.
- </para>
- </listitem>
- <listitem>
- <para>
- Test exit specifiers - control the conditions for test
- completion, including the number of initiated exchanges,
- the test period orthe maximum number of dropped packets.
- </para>
- </listitem>
- <listitem>
- <para>
- Packet templates - specify files containing packet templates that
- are used by perfdhcp to create custom DHCP messages. The tool
- allows the specification of a number of values indicating
- offsets of values within a packet that are set by the tool.
- </para>
- </listitem>
- <listitem>
- <para>
- Reporting - for each test produce a set of performance data
- including the achieved packet exchange rate (server performance).
- There are a number of diagnostic selectors available that
- enable periodic (intermediate) reporting, printing of packet timestamps,
- and the listing of detailed information about internal perfdhcp
- states (for debugging).
- </para>
- </listitem>
- <listitem>
- <para>
- Different mode of operations - specify the DHCP protocol used
- (v4 or v6), two-way or four-way exchanges, use of the
- Rapid Commit option for DHCPv6.
- </para>
- </listitem>
- <listitem>
- <para>
- IP layer options - specify the local/remote address, local interface
- and local port to be used for communication with DHCP server.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </section>
- <section id="perfdhcp-command-line">
- <title>Command line options</title>
- <para>
- The following "help" output from the tool describes the
- command line switches. This summary also lists the tool's
- possible exit codes as well as describing the
- error counters printed when the test is complete:
- <screen>$ <userinput>perfdhcp -h</userinput>
-<![CDATA[perfdhcp [-hv] [-4|-6] [-r<rate>] [-t<report>] [-R<range>] [-b<base>]
- [-n<num-request>] [-p<test-period>] [-d<drop-time>] [-D<max-drop>]
- [-l<local-addr|interface>] [-P<preload>] [-a<aggressivity>]
- [-L<local-port>] [-s<seed>] [-i] [-B] [-c] [-1]
- [-T<template-file>] [-X<xid-offset>] [-O<random-offset]
- [-E<time-offset>] [-S<srvid-offset>] [-I<ip-offset>]
- [-x<diagnostic-selector>] [-w<wrapped>] [server]
-
-The [server] argument is the name/address of the DHCP server to
-contact. For DHCPv4 operation, exchanges are initiated by
-transmitting a DHCP DISCOVER to this address.
-
-For DHCPv6 operation, exchanges are initiated by transmitting a DHCP
-SOLICIT to this address. In the DHCPv6 case, the special name 'all'
-can be used to refer to All_DHCP_Relay_Agents_and_Servers (the
-multicast address FF02::1:2), or the special name 'servers' to refer
-to All_DHCP_Servers (the multicast address FF05::1:3). The [server]
-argument is optional only in the case that -l is used to specify an
-interface, in which case [server] defaults to 'all'.
-
-The default is to perform a single 4-way exchange, effectively pinging
-the server.
-The -r option is used to set up a performance test, without
-it exchanges are initiated as fast as possible.
-
-Options:
--1: Take the server-ID option from the first received message.
--4: DHCPv4 operation (default). This is incompatible with the -6 option.
--6: DHCPv6 operation. This is incompatible with the -4 option.
--a<aggressivity>: When the target sending rate is not yet reached,
- control how many exchanges are initiated before the next pause.
--b<base>: The base mac, duid, IP, etc, used to simulate different
- clients. This can be specified multiple times, each instance is
- in the <type>=<value> form, for instance:
- (and default) mac=00:0c:01:02:03:04.
--d<drop-time>: Specify the time after which a request is treated as
- having been lost. The value is given in seconds and may contain a
- fractional component. The default is 1 second.
--E<time-offset>: Offset of the (DHCPv4) secs field / (DHCPv6)
- elapsed-time option in the (second/request) template.
- The value 0 disables it.
--h: Print this help.
--i: Do only the initial part of an exchange: DO or SA, depending on
- whether -6 is given.
--I<ip-offset>: Offset of the (DHCPv4) IP address in the requested-IP
- option / (DHCPv6) IA_NA option in the (second/request) template.
--l<local-addr|interface>: For DHCPv4 operation, specify the local
- hostname/address to use when communicating with the server. By
- default, the interface address through which traffic would
- normally be routed to the server is used.
- For DHCPv6 operation, specify the name of the network interface
- via which exchanges are initiated.
--L<local-port>: Specify the local port to use
- (the value 0 means to use the default).
--O<random-offset>: Offset of the last octet to randomize in the template.
--P<preload>: Initiate first <preload> exchanges back to back at startup.
--r<rate>: Initiate <rate> DORA/SARR (or if -i is given, DO/SA)
- exchanges per second. A periodic report is generated showing the
- number of exchanges which were not completed, as well as the
- average response latency. The program continues until
- interrupted, at which point a final report is generated.
--R<range>: Specify how many different clients are used. With 1
- (the default), all requests seem to come from the same client.
--s<seed>: Specify the seed for randomization, making it repeatable.
--S<srvid-offset>: Offset of the server-ID option in the
- (second/request) template.
--T<template-file>: The name of a file containing the template to use
- as a stream of hexadecimal digits.
--v: Report the version number of this program.
--w<wrapped>: Command to call with start/stop at the beginning/end of
- the program.
--x<diagnostic-selector>: Include extended diagnostics in the output.
- <diagnostic-selector> is a string of single-keywords specifying
- the operations for which verbose output is desired. The selector
- keyletters are:
- * 'a': print the decoded command line arguments
- * 'e': print the exit reason
- * 'i': print rate processing details
- * 'r': print randomization details
- * 's': print first server-id
- * 't': when finished, print timers of all successful exchanges
- * 'T': when finished, print templates
--X<xid-offset>: Transaction ID (aka. xid) offset in the template.
-
-DHCPv4 only options:
--B: Force broadcast handling.
-
-DHCPv6 only options:
--c: Add a rapid commit option (exchanges will be SA).
-
-The remaining options are used only in conjunction with -r:
-
--D<max-drop>: Abort the test if more than <max-drop> requests have
- been dropped. Use -D0 to abort if even a single request has been
- dropped. If <max-drop> includes the suffix '%', it specifies a
- maximum percentage of requests that may be dropped before abort.
- In this case, testing of the threshold begins after 10 requests
- have been expected to be received.
--n<num-request>: Initiate <num-request> transactions. No report is
- generated until all transactions have been initiated/waited-for,
- after which a report is generated and the program terminates.
--p<test-period>: Send requests for the given test period, which is
- specified in the same manner as -d. This can be used as an
- alternative to -n, or both options can be given, in which case the
- testing is completed when either limit is reached.
--t<report>: Delay in seconds between two periodic reports.
-
-Errors:
-- tooshort: received a too short message
-- orphans: received a message which doesn't match an exchange
- (duplicate, late or not related)
-- locallimit: reached to local system limits when sending a message.
-
-Exit status:
-The exit status is:
-0 on complete success.
-1 for a general error.
-2 if an error is found in the command line arguments.
-3 if there are no general failures in operation, but one or more
- exchanges are not successfully completed.
-]]>
- </screen>
- </para>
- </section>
- <section id="starting-perfdhcp">
- <title>Starting perfdhcp</title>
- <para>
- In order to run a performance test, at least two separate systems
- have to be installed: client and server. The first one must have
- perfdhcp installed, and the latter must be running the DHCP server
- (either v4 or v6). If only single system is available the client
- and server can be run on virtual machines (running on the same
- physical system) but in this case performance data may be heavily
- impacted by the overhead involved in running such the virtual
- machines.
- </para>
- <para>
- Currently, perfdhcp is seen from the server perspective as relay agent.
- This simplifies its implementation: specifically there is no need to
- receive traffic sent to broadcast addresses. However, it does impose
- a requirement that the IPv4
- address has to be set manually on the interface that will be used to
- communicate with the server. For example, if the DHCPv4 server is listening
- on the interface connected to the 172.16.1.0 subnet, the interface on client
- machine has to have network address assigned from the same subnet, e.g.
- <screen><userinput>#ifconfig eth3 172.16.1.2. netmask 255.255.255.0 up</userinput></screen>
- </para>
- <para>
- As DHCP uses low port numbers (67 for DHCPv4 relays and
- 547 for DHCPv6), running perfdhcp with non-root privileges will
- usually result in the error message similar to this:
- <screen><userinput>$ perfdhcp -4 -l eth3 -r 100 all</userinput>
-Error running perfdhcp: Failed to bind socket 3 to 172.16.1.2/port=67
- </screen>
- The '-L' command line switch allows the use of a custom local port.
- However, although the following command line will work:
- <screen><userinput>$ perfdhcp -4 -l eth3 -r 100 -L 10067 all</userinput></screen>
- in the standard configuration no responses will be received
- from the DHCP server because the server responds to default relay
- port 67. A way to overcome this issue is to run
- perfdhcp as root.
- </para>
-
- </section>
- <section id="perfdhcp-commandline-examples">
- <title>perfdhcp command line examples</title>
- <para>
- In this section, a number of perfdhcp command line examples
- are presented as a quick start guide for new users. For the
- detailed list of command line options refer to
- <xref linkend="perfdhcp-command-line"/>.
- </para>
- <section id="perfdhcp-basic-usage">
- <title>Example: basic usage</title>
- <para>
- If server is listening on interface with IPv4 address 172.16.1.1,
- the simplest perfdhcp command line will look like:
- <screen><userinput># perfdhcp 172.16.1.1</userinput>
-***Rate statistics***
-Rate: 206.345
-
-***Statistics for: DISCOVER-OFFER***
-sent packets: 21641
-received packets: 350
-drops: 21291
-orphans: 0
-
-min delay: 9.022 ms
-avg delay: 143.100 ms
-max delay: 259.303 ms
-std deviation: 56.074 ms
-collected packets: 30
-
-***Statistics for: REQUEST-ACK***
-sent packets: 350
-received packets: 268
-drops: 82
-orphans: 0
-
-min delay: 3.010 ms
-avg delay: 152.470 ms
-max delay: 258.634 ms
-std deviation: 56.936 ms
-collected packets: 0
- </screen>
- Here, perfdhcp uses remote address 172.16.1.1 as a
- destination address and will use a suitable local interface for
- communication. Since, no rate control parameters have been specified,
- it will initiate DHCP exchanges at the maximum possible rate. Due to the server's
- performance limitation, it is likely that many of the packets will be dropped.
- The performance test will continue running until it is
- interrupted by the user (with ^C).
- </para>
- <para>
- The default performance statistics reported by perfdhcp have the
- following meaning:
- <itemizedlist>
- <listitem><para>Rate - number of packet exchanges (packet sent
- to the server and matching response received from the server)
- completed within a second.</para></listitem>
- <listitem><para>sent packets - total number of DHCP packets of
- a specific type sent to the server.</para></listitem>
- <listitem><para>received packets - total number of DHCP packets
- of specific type received from the server.</para></listitem>
- <listitem><para>drops - number of dropped packets for the
- particular exchange. The number of dropped packets is calculated as
- the difference between the number of sent packets and number of
- response packets received from the server. In some cases, the
- server will have sent a reponse but perfdhcp execution ended before
- the reponse arrived. In such case this packet will be counted
- as dropped.</para></listitem>
- <listitem><para>orphans - number of packets that have been
- received from the server and did not match any packet sent by
- perfdhcp. This may occur if received packet has been sent
- to some other host or if then exchange timed out and
- the sent packet was removed from perfdhcp's list of packets
- awaiting a response.</para></listitem>
- <listitem><para>min delay - minimum delay that occured between
- sending the packet to the server and receiving a reponse from
- it.</para></listitem>
- <listitem><para>avg delay - average delay between sending the
- packet of the specific type the server and receiving a response
- from it.</para></listitem>
- <listitem><para>max delay - maximum delay that occured between
- sending the packet to the server and receiving a response from
- it.</para></listitem>
- <listitem><para>std deviation - standard deviation of the delay
- between sending the packet of a specific type to the server and
- receiving response from it.</para></listitem>
- <listitem><para>collected packets - number of sent packets that
- were garbage collected. Packets may get garbage collected when
- the waiting time for server a response exceeds value set with the
- '-d' (drop time) switch.
- <![CDATA[-d<drop-time>]]>.</para></listitem>
- </itemizedlist>
- </para>
- <para>
- Note: should multiple interfaces on the system running perfdhcp be
- connected to the same subnet, the interface to be used for the test
- can be specified using either the interface name:
- <screen><userinput># perfdhcp -l eth3</userinput></screen>
- or a local address assigned to it:
- <screen><userinput># perfdhcp -l 172.16.1.2</userinput></screen>
- </para>
- </section>
- <section id="perfdhcp-rate-control">
- <title>Example: rate control</title>
- <para>
- In the examples above perfdhcp initiates new exchanges with a best
- effort rate. With this setting, many packets are expected to be dropped
- by the server due to performance limitations. In many cases though, it is
- desired to verify that the server can handle an expected (reasonable) rate
- without dropping any packets. The following command is an example of such
- a test: it causes perfdhcp to initiate 300 four-way exchanges
- per second, and runs the test for 60 seconds:
- <screen><userinput># perfdhcp -l eth3 -p 60 -r 300</userinput>
-***Rate statistics***
-Rate: 256.683 exchanges/second, expected rate: 300 exchanges/second
-
-***Statistics for: DISCOVER-OFFER***
-sent packets: 17783
-received packets: 15401
-drops: 2382
-orphans: 0
-
-min delay: 0.109 ms
-avg delay: 75.756 ms
-max delay: 575.614 ms
-std deviation: 60.513 ms
-collected packets: 11
-
-***Statistics for: REQUEST-ACK***
-sent packets: 15401
-received packets: 15317
-drops: 84
-orphans: 0
-
-min delay: 0.536 ms
-avg delay: 72.072 ms
-max delay: 576.749 ms
-std deviation: 58.189 ms
-collected packets: 0
- </screen>
- Note that here, the packet drops for the DISCOVER-OFFER
- exchange have been significantly reduced (when compared with the
- output from the previous example) thanks to the setting of a
- reasonable rate. The non-zero number of packet drops and achieved
- rate (256/s) indicate that server's measured performance is lower than 300 leases
- per second. A further rate decrease should eliminate most of the packet
- drops and bring the achieved rate close to expected rate:
- <screen><userinput># perfdhcp -l eth3 -p 60 -r 100 -R 30</userinput>
-***Rate statistics***
-Rate: 99.8164 exchanges/second, expected rate: 100 exchanges/second
-
-***Statistics for: DISCOVER-OFFER***
-sent packets: 5989
-received packets: 5989
-drops: 0
-orphans: 0
-
-min delay: 0.023 ms
-avg delay: 2.198 ms
-max delay: 181.760 ms
-std deviation: 9.429 ms
-collected packets: 0
-
-***Statistics for: REQUEST-ACK***
-sent packets: 5989
-received packets: 5989
-drops: 0
-orphans: 0
-
-min delay: 0.473 ms
-avg delay: 2.355 ms
-max delay: 189.658 ms
-std deviation: 5.876 ms
-collected packets: 0
- </screen>
- There are now no packet drops, confirming that the server is able to
- handle a load of 100 leases/second.
- Note that the last parameter (-R 30) configures perfdhcp to simulate
- traffic from 30 distinct clients.
- </para>
- </section>
- <section id="perfdhcp-templates">
- <title>Example: templates</title>
- <para>
- By default the DHCP messages are formed with default options. With
- template files, it is possible to define a custom packet format.
- </para>
- <para>
- The template file names are specified with <![CDATA[-T<template-file>]]>
- command line option. This option can be specified zero, one or two times.
- The first occurence of this option refers to DISCOVER or SOLICIT message
- and the second occurence refers to REQUEST (DHCPv4 or DHCPv6) message.
- If -T option occurs only once the DISCOVER or SOLICIT message will be
- created from the template and the REQUEST message will be created
- dynamically (without the template). Note that each template file
- holds data for exactly one DHCP message type. Templates for multiple
- message types must not be combined in the single file.
- The content in template files is encoded as series of ASCII hexadecimal
- digits (each byte represented by two ASCII chars 00..FF). Data in a
- template file is laid in network byte order and it can be used on the
- systems with different endianness.
- perfdhcp forms the packet by replacing parts of the message buffer read
- from the file with variable data such as elapsed time, hardware address, DUID
- etc. The offsets where such variable data is placed is specific to the
- template file and have to be specified from the command line. Refer to
- <xref linkend="perfdhcp-command-line"/> to find out how to
- specify offsets for particular options and fields. With the following
- command line the DHCPv6 SOLICIT and REQUEST packets will be formed from
- solicit.hex and request6.hex packets:
- <screen><userinput># perfdhcp -6 -l eth3 -r 100 -R 20 -T solicit.hex -T request6.hex -O 21 -E 84 -S 22 -I 40 servers</userinput>
-***Rate statistics***
-Rate: 99.5398 exchanges/second, expected rate: 100 exchanges/second
-
-***Statistics for: SOLICIT-ADVERTISE***
-sent packets: 570
-received packets: 569
-drops: 1
-orphans: 0
-
-min delay: 0.259 ms
-avg delay: 0.912 ms
-max delay: 6.979 ms
-std deviation: 0.709 ms
-collected packets: 0
-
-***Statistics for: REQUEST-REPLY***
-sent packets: 569
-received packets: 569
-drops: 0
-orphans: 0
-
-min delay: 0.084 ms
-avg delay: 0.607 ms
-max delay: 6.490 ms
-std deviation: 0.518 ms
-collected packets: 0
- </screen>
- where the switches have the following meaning:
- <itemizedlist>
- <listitem><para>two occurences of -O 21 - DUID's last octet
- positions in SOLICIT and REQUEST respectively.</para></listitem>
- <listitem><para>-E 84 - elapsed time option position in the
- REQUEST template</para></listitem>
- <listitem><para>-S 22 - server id position in the REQUEST
- template</para></listitem>
- <listitem><para>-I 40 - IA_NA option position in the REQUEST
- template</para></listitem>
- </itemizedlist>
- </para>
- <para>
- The offsets of options indicate where they begin in the packet.
- The only exception from this rule is <![CDATA[-O<random-offset>]]>
- option that specifies the end of the DUID (DHCPv6) or MAC address
- (DHCPv4). Depending on the number of simulated clients
- (see <![CDATA[-R<random-range>]]> command line option) perfdhcp
- will be randomizing bytes in packet buffer starting from this
- position backwards. For the number of simulated clients
- <![CDATA[<=]]> 256 only one octet (at random-offset position)
- will be ranomized, for the number of clients <![CDATA[<=]]> 65536
- two octets (at random-offset and random-offset-1)
- will be randmized etc.
- </para>
- </section>
- </section>
- </chapter>
-</book>
diff --git a/tests/tools/dhcp-ubench/memfile_ubench.cc b/tests/tools/dhcp-ubench/memfile_ubench.cc
deleted file mode 100644
index aa3377fbd1..0000000000
--- a/tests/tools/dhcp-ubench/memfile_ubench.cc
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright (C) 2012, 2015 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 <sstream>
-#include <iostream>
-#include <map>
-#include "memfile_ubench.h"
-
-using namespace std;
-
-
-/// @brief In-memory + lease file database implementation
-///
-/// This is a simplified in-memory database that mimics ISC DHCP4 implementation.
-/// It uses STL and boost: std::map for storage, boost::shared ptr for memory
-/// management. It does use C file operations (fopen, fwrite, etc.), because
-/// C++ streams does not offer any easy way to flush their contents, like
-/// fflush() and fsync() does.
-///
-/// IPv4 address is used as a key in the hash.
-class memfile_LeaseMgr {
-public:
-
- /// A hash table for Lease4 leases.
- typedef std::map<uint32_t /* addr */, Lease4Ptr /* lease info */> IPv4Hash;
-
- /// An iterator for Lease4 hash table.
- typedef std::map<uint32_t, Lease4Ptr>::iterator leaseIt;
-
- /// @brief The sole memfile lease manager constructor
- ///
- /// @param filename name of the lease file (will be overwritten)
- /// @param sync should operations be
- memfile_LeaseMgr(const std::string& filename, bool sync);
-
- /// @brief Destructor (closes file)
- ~memfile_LeaseMgr();
-
- /// @brief adds a lease to the hash
- ///
- /// @param lease lease to be added
- bool addLease(Lease4Ptr lease);
-
- /// @brief returns existing lease
- ///
- /// @param addr address of the searched lease
- ///
- /// @return smart pointer to the lease (or NULL if lease is not found)
- Lease4Ptr getLease(uint32_t addr);
-
- /// @brief Simplified lease update.
- ///
- /// Searches for a lease and then updates its client last transmission
- /// time. Writes new lease content to lease file (and calls fflush()/fsync(),
- /// if synchronous operation is enabled).
- ///
- /// @param addr IPv4 address
- /// @param new_cltt New client last transmission time
- ///
- /// @return pointer to the updated lease (or NULL)
- Lease4Ptr updateLease(uint32_t addr, uint32_t new_cltt);
-
- /// @brief Deletes a lease.
- ///
- /// @param addr IPv4 address of the lease to be deleted.
- ///
- /// @return true if deletion was successful, false if no such lease exists
- bool deleteLease(uint32_t addr);
-
-protected:
-
- /// @brief Writes updated lease to a file.
- ///
- /// @param lease lease to be written
- void writeLease(Lease4Ptr lease);
-
- /// Name of the lease file.
- std::string filename_;
-
- /// should we do flush after each operation?
- bool sync_;
-
- /// File handle to the open lease file.
- FILE * file_;
-
- /// Hash table for IPv4 leases
- IPv4Hash ip4Hash_;
-};
-
-memfile_LeaseMgr::memfile_LeaseMgr(const std::string& filename, bool sync)
- : filename_(filename), sync_(sync) {
- file_ = fopen(filename.c_str(), "w");
- if (!file_) {
- throw "Failed to create file " + filename;
- }
-
-}
-
-memfile_LeaseMgr::~memfile_LeaseMgr() {
- fclose(file_);
-}
-
-void memfile_LeaseMgr::writeLease(Lease4Ptr lease) {
- fprintf(file_, "lease %d {\n hw-addr ", lease->addr);
- for (std::vector<uint8_t>::const_iterator it = lease->hwaddr.begin();
- it != lease->hwaddr.end(); ++it) {
- fprintf(file_, "%02x:", *it);
- }
- fprintf(file_, ";\n client-id ");
- for (std::vector<uint8_t>::const_iterator it = lease->client_id.begin();
- it != lease->client_id.end(); ++it) {
- fprintf(file_, "%02x:", *it);
- }
- fprintf(file_, ";\n valid-lifetime %d;\n recycle-time %d;\n"
- " cltt %d;\n pool-id %d;\n fixed %s; hostname %s;\n"
- " fqdn_fwd %s;\n fqdn_rev %s;\n};\n",
- lease->valid_lft, lease->recycle_time, (int)lease->cltt,
- lease->pool_id, lease->fixed?"true":"false",
- lease->hostname.c_str(), lease->fqdn_fwd?"true":"false",
- lease->fqdn_rev?"true":"false");
-
- if (sync_) {
- fflush(file_);
- fsync(fileno(file_));
- }
-}
-
-bool memfile_LeaseMgr::addLease(Lease4Ptr lease) {
- if (ip4Hash_.find(lease->addr) != ip4Hash_.end()) {
- // there is such an address already in the hash
- return false;
- }
- ip4Hash_.insert(pair<uint32_t, Lease4Ptr>(lease->addr, lease));
- lease->hostname = "add";
- writeLease(lease);
- return (true);
-}
-
-Lease4Ptr memfile_LeaseMgr::getLease(uint32_t addr) {
- leaseIt x = ip4Hash_.find(addr);
- if (x != ip4Hash_.end()) {
- return x->second; // found
- }
-
- // not found
- return Lease4Ptr();
-}
-
-Lease4Ptr memfile_LeaseMgr::updateLease(uint32_t addr, uint32_t new_cltt) {
- leaseIt x = ip4Hash_.find(addr);
- if (x != ip4Hash_.end()) {
- x->second->cltt = new_cltt;
- x->second->hostname = "update";
- writeLease(x->second);
- return x->second;
- }
- return Lease4Ptr();
-}
-
-bool memfile_LeaseMgr::deleteLease(uint32_t addr) {
- leaseIt x = ip4Hash_.find(addr);
- if (x != ip4Hash_.end()) {
- x->second->hostname = "delete";
- writeLease(x->second);
- ip4Hash_.erase(x);
- return true;
- }
- return false;
-}
-
-memfile_uBenchmark::memfile_uBenchmark(const string& filename,
- uint32_t num_iterations,
- bool sync,
- bool verbose)
- :uBenchmark(num_iterations, filename, sync, verbose) {
-}
-
-void memfile_uBenchmark::connect() {
- try {
- leaseMgr_ = new memfile_LeaseMgr(dbname_, sync_);
- } catch (const std::string& e) {
- failure(e.c_str());
- }
-}
-
-void memfile_uBenchmark::disconnect() {
- delete leaseMgr_;
- leaseMgr_ = NULL;
-}
-
-void memfile_uBenchmark::createLease4Test() {
- if (!leaseMgr_) {
- throw "No LeaseMgr instantiated.";
- }
-
- uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
- const uint8_t hwaddr_len = 20; // Not a real field
- char hwaddr_tmp[hwaddr_len];
- const uint8_t client_id_len = 128;
- char client_id_tmp[client_id_len];
- uint32_t valid_lft = 1000; // We can use the same value for all leases
- uint32_t recycle_time = 0; // Not supported in any foreseeable future,
- // so keep this as 0
- time_t cltt = time(NULL); // Timestamp
- uint32_t pool_id = 0; // Let's use pools 0-99
- bool fixed = false;
- string hostname("foo"); // Will generate it dynamically
- bool fqdn_fwd = true; // Let's pretend to do AAAA update
- bool fqdn_rev = true; // Let's pretend to do PTR update
-
- cout << "CREATE: ";
-
- // While we could put the data directly into vector, I would like to
- // keep the code as similar to other benchmarks as possible
- for (uint8_t i = 0; i < hwaddr_len; ++i) {
- hwaddr_tmp[i] = 'A' + i; // let's make hwaddr consisting of letter
- }
- vector<uint8_t> hwaddr(hwaddr_tmp, hwaddr_tmp + hwaddr_len - 1);
-
- for (uint8_t i = 0; i < client_id_len; i++) {
- client_id_tmp[i] = 33 + i; // 33 is being the first, non whitespace
- // printable ASCII character
- }
- vector<uint8_t> client_id(client_id_tmp, client_id_tmp + client_id_len - 1);
-
- for (uint32_t i = 0; i < num_; ++i) {
-
- cltt++;
-
- Lease4Ptr lease = boost::shared_ptr<Lease4>(new Lease4());
- lease->addr = addr;
- lease->hwaddr = hwaddr;
- lease->client_id = client_id;
- lease->valid_lft = valid_lft;
- lease->recycle_time = recycle_time;
- lease->cltt = cltt;
- lease->pool_id = pool_id;
- lease->fixed = fixed;
- lease->hostname = hostname;
- lease->fqdn_fwd = fqdn_fwd;
- lease->fqdn_rev = fqdn_rev;
-
- if (!leaseMgr_->addLease(lease)) {
- failure("addLease() failed");
- } else {
- if (verbose_) {
- cout << ".";
- }
- };
-
- addr++;
- }
- cout << endl;
-}
-
-void memfile_uBenchmark::searchLease4Test() {
- if (!leaseMgr_) {
- throw "No LeaseMgr instantiated.";
- }
-
- cout << "RETRIEVE: ";
-
- for (uint32_t i = 0; i < num_; i++) {
- uint32_t x = BASE_ADDR4 + random() % int(num_ / hitratio_);
-
- Lease4Ptr lease = leaseMgr_->getLease(x);
- if (verbose_) {
- cout << (lease?".":"X");
- }
- }
-
- cout << endl;
-}
-
-void memfile_uBenchmark::updateLease4Test() {
- if (!leaseMgr_) {
- throw "No LeaseMgr instantiated.";
- }
-
- cout << "UPDATE: ";
-
- time_t cltt = time(NULL);
-
- for (uint32_t i = 0; i < num_; i++) {
-
- uint32_t x = BASE_ADDR4 + random() % num_;
-
- Lease4Ptr lease = leaseMgr_->updateLease(x, cltt);
- if (!lease) {
- stringstream tmp;
- tmp << "UPDATE failed for lease " << hex << x << dec;
- failure(tmp.str().c_str());
- }
- if (verbose_) {
- cout << ".";
- }
- }
-
- cout << endl;
-}
-
-void memfile_uBenchmark::deleteLease4Test() {
- if (!leaseMgr_) {
- throw "No LeaseMgr instantiated.";
- }
-
- cout << "DELETE: ";
-
- for (uint32_t i = 0; i < num_; i++) {
-
- uint32_t x = BASE_ADDR4 + i;
-
- if (!leaseMgr_->deleteLease(x)) {
- stringstream tmp;
- tmp << "UPDATE failed for lease " << hex << x << dec;
- failure(tmp.str().c_str());
- }
- if (verbose_) {
- cout << ".";
- }
- }
-
- cout << endl;
-}
-
-void memfile_uBenchmark::printInfo() {
- cout << "Memory db (using std::map) + write-only file." << endl;
-}
-
-
-int main(int argc, char * const argv[]) {
-
- const char * filename = "dhcpd.leases";
- uint32_t num = 100;
- bool sync = true;
- bool verbose = false;
-
- memfile_uBenchmark bench(filename, num, sync, verbose);
-
- bench.parseCmdline(argc, argv);
-
- int result = bench.run();
-
- return (result);
-}
diff --git a/tests/tools/dhcp-ubench/memfile_ubench.h b/tests/tools/dhcp-ubench/memfile_ubench.h
deleted file mode 100644
index 51b73134fc..0000000000
--- a/tests/tools/dhcp-ubench/memfile_ubench.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// 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 <string>
-#include <fstream>
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include "benchmark.h"
-
-/// @brief Structure of the Lease4 that is kept in memory
-struct Lease4 {
- uint32_t addr; /// IPv4 address
- std::vector<uint8_t> hwaddr; /// hardware address
- std::vector<uint8_t> client_id; /// client-identifier
- uint32_t valid_lft; /// valid lifetime timestamp
- uint32_t recycle_time; /// timer for keeping lease after expiration/release
- /// (currently not used)
- time_t cltt; /// client last transmission time
- uint32_t pool_id; /// ID of the pool the lease belongs to
- bool fixed; /// is this lease fixed?
- std::string hostname; /// client hostname (may be empty)
- bool fqdn_fwd; /// did we do AAAA update for this lease?
- bool fqdn_rev; /// did we do PTR update for this lease?
- std::string options; /// additional options stored with this lease
- /// (currently not used)
- std::string comments; /// comments on that lease
- /// (currently not used)
-};
-
-/// Pointer to a Lease4 structure
-typedef boost::shared_ptr<Lease4> Lease4Ptr;
-
-/// an implementation of in-memory+file database
-/// The actual implementation is in memfile_ubench.cc
-class memfile_LeaseMgr;
-
-/// @brief In-memory + file micro-benchmark.
-///
-/// That is a specific backend implementation. See \ref uBenchmark class for
-/// detailed explanation of its operations. This class uses custom in-memory
-/// pseudo-database and external write-only lease file. That approach simulates
-/// modernized model of ISC DHCP4. It uses standard STL maps together with
-/// shared_ptr from boost library. The "database" is implemented in the Lease
-/// Manager (see \ref LeaseMgr in memfile_ubench.cc). All lease changes are
-/// appended to the end of the file, speeding up the process.
-class memfile_uBenchmark: public uBenchmark {
-public:
-
- /// @brief The sole memfile benchmark constructor.
- ///
- /// @param filename name of the write-only lease file
- /// @param num_iterations number of iterations
- /// @param sync should fsync() be called after every file write?
- /// @param verbose would you like extra logging?
- memfile_uBenchmark(const std::string& filename,
- uint32_t num_iterations, bool sync, bool verbose);
-
- /// @brief Prints backend info.
- virtual void printInfo();
-
- /// @brief Spawns lease manager that create empty lease file, initializes
- /// empty STL maps.
- virtual void connect();
-
- /// @brief Delete lease manager that closes lease file.
- virtual void disconnect();
-
- /// @brief Creates new leases.
- ///
- /// See uBenchmark::createLease4Test() for detailed explanation.
- virtual void createLease4Test();
-
- /// @brief Searches for existing leases.
- ///
- /// See uBenchmark::searchLease4Test() for detailed explanation.
- virtual void searchLease4Test();
-
- /// @brief Updates existing leases.
- ///
- /// See uBenchmark::updateLease4Test() for detailed explanation.
- virtual void updateLease4Test();
-
- /// @brief Deletes existing leases.
- ///
- /// See uBenchmark::deleteLease4Test() for detailed explanation.
- virtual void deleteLease4Test();
-
-protected:
-
- /// Lease Manager (concrete backend implementation, based on STL maps)
- memfile_LeaseMgr * leaseMgr_;
-};
diff --git a/tests/tools/dhcp-ubench/mysql.schema b/tests/tools/dhcp-ubench/mysql.schema
deleted file mode 100644
index ed01e46cf1..0000000000
--- a/tests/tools/dhcp-ubench/mysql.schema
+++ /dev/null
@@ -1,86 +0,0 @@
-DROP DATABASE kea;
-CREATE DATABASE kea;
-
-CONNECT kea;
-
-CREATE TABLE lease4 (
-
- # Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
- lease_id SERIAL,
- addr INT UNSIGNED UNIQUE,
-
- # The largest hardware address is for Infiniband (20 bytes)
- hwaddr VARCHAR(20),
-
- # The largest client-id is DUID in DHCPv6 - up to 128 bytes
- client_id VARCHAR(128),
-
- # Expressed in seconds
- valid_lft INT,
-
- # Expressed in seconds,
- recycle_time INT DEFAULT 0,
-
- cltt TIMESTAMP,
-
- pool_id int,
-
- fixed BOOL,
-
- # DDNS stuff
- hostname VARCHAR(255),
- fqdn_fwd BOOL DEFAULT false,
- fqdn_rev BOOL DEFAULT false,
-
- options TEXT,
- comments TEXT
-);
-
-CREATE TABLE lease6 (
-
- # Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
- lease_id SERIAL,
- addr CHAR(16) BYTE UNIQUE,
-
- # The largest hardware address is for Infiniband (20 bytes)
- hwaddr VARCHAR(20),
-
- # The largest client-id is DUID in DHCPv6 - up to 128 bytes
- client_id VARCHAR(128),
-
- iaid int unsigned,
-
- # Used for IA_PD only (tinyint = 0..255)
- prefix_len TINYINT unsigned,
-
- # Expressed in seconds
- preferred_lft INT,
-
- # Expressed in seconds
- valid_lft INT,
-
- # Expressed in seconds,
- recycle_time INT DEFAULT 0,
-
- cltt TIMESTAMP,
-
- pool_id int,
-
- fixed BOOL DEFAULT false,
-
- hostname VARCHAR(255),
- fqdn_fwd BOOL DEFAULT false,
- fqdn_rev BOOL DEFAULT false,
-
- options TEXT,
- comments TEXT
-);
-
-CREATE TABLE host (
- address BIGINT NULL,
- address6 BIGINT NULL,
- prefix6 BIGINT NULL,
- hostname VARCHAR(255),
- options TEXT,
- comments TEXT
-); \ No newline at end of file
diff --git a/tests/tools/dhcp-ubench/mysql_ubench.cc b/tests/tools/dhcp-ubench/mysql_ubench.cc
deleted file mode 100644
index b2f58c2e72..0000000000
--- a/tests/tools/dhcp-ubench/mysql_ubench.cc
+++ /dev/null
@@ -1,674 +0,0 @@
-// 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 <iostream>
-#include <sstream>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <mysql.h>
-
-#include "benchmark.h"
-#include "mysql_ubench.h"
-
-using namespace std;
-
-MySQL_uBenchmark::MySQL_uBenchmark(const string& hostname, const string& user,
- const string& pass, const string& db,
- uint32_t num_iterations, bool sync,
- bool verbose)
- :uBenchmark(num_iterations, db, sync, verbose, hostname, user, pass),
- conn_(NULL) {
-
-}
-
-void MySQL_uBenchmark::stmt_failure(MYSQL_STMT * stmt, const char* operation) {
- stringstream tmp;
- tmp << "Error " << mysql_stmt_errno(stmt) << " during " << operation
- << ": " << mysql_stmt_error(stmt);
- throw tmp.str();
-}
-
-
-
-void MySQL_uBenchmark::failure(const char* operation) {
- stringstream tmp;
- tmp << "Error " << mysql_errno(conn_) << " during " << operation
- << ": " << mysql_error(conn_);
- throw tmp.str();
-}
-
-void MySQL_uBenchmark::connect() {
-
- conn_ = mysql_init(NULL);
- if (!conn_) {
- failure("initializing MySQL library");
- } else {
- cout << "MySQL library init successful." << endl;
- }
-
- if (!mysql_real_connect(conn_, hostname_.c_str(), user_.c_str(),
- passwd_.c_str(), dbname_.c_str(), 0, NULL, 0)) {
- failure("connecting to MySQL server");
- } else {
- cout << "MySQL connection established." << endl;
- }
-
- string q = "delete from lease4;";
- if (mysql_real_query(conn_, q.c_str(), strlen(q.c_str()))) {
- failure("dropping old lease4 entries.");
- }
-
- q = "ALTER TABLE lease4 engine=";
- if (sync_) {
- q += "InnoDB";
- } else {
- q += "MyISAM";
- }
- if (mysql_query(conn_, q.c_str())) {
- q = "Failed to run query:" + q;
- failure(q.c_str());
- }
-}
-
-void MySQL_uBenchmark::disconnect() {
- if (!conn_) {
- throw "NULL MySQL connection pointer.";
- }
- mysql_close(conn_);
- conn_ = NULL;
-}
-
-void MySQL_uBenchmark::createLease4Test() {
- if (!conn_) {
- throw "Not connected to MySQL server.";
- }
-
- uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
- char hwaddr[20];
- size_t hwaddr_len = 20; // Not a real field
- char client_id[128];
- size_t client_id_len = 128;
- uint32_t valid_lft = 1000; // We can use the same value for all leases
- uint32_t recycle_time = 7; // not supported in any foresable future,
-
- char cltt[48]; // timestamp (specified as text)
- size_t cltt_len;
-
- sprintf(cltt, "2012-07-11 15:43:00");
- cltt_len = strlen(cltt);
-
- uint32_t pool_id = 1000; // Let's use pool-ids greater than zero
- bool fixed = false;
-
- char hostname[] = "foo"; // Will generate it dynamically
- size_t hostname_len;
- hostname_len = strlen(hostname);
-
- bool fqdn_fwd = true; // Let's pretend to do AAAA update
- bool fqdn_rev = true; // Let's pretend to do PTR update
-
- cout << "CREATE: ";
-
- for (uint8_t i = 0; i < hwaddr_len; i++) {
- hwaddr[i] = 'A' + i; // let's make hwaddr consisting of letters
- }
- hwaddr[19] = 0; // make it is null-terminated
-
- for (uint8_t i = 0; i < client_id_len; i++) {
- client_id[i] = 33 + i; // 33 is being the first, non whitespace
- // printable ASCII character
- }
- client_id[127] = 0; // make it is null-terminated
-
- MYSQL_STMT * stmt = NULL;
- MYSQL_BIND bind[11]; // 11 parameters in the insert statement
-
- if (compiled_stmt_) {
- // create a statement once
- stmt = mysql_stmt_init(conn_);
- if (!stmt) {
- failure("Unable to create compiled statement, mysql_stmt_init() failed");
- }
-
- const char * statement = "INSERT INTO lease4(addr,hwaddr,client_id,"
- "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
- "fqdn_fwd,fqdn_rev) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
-
- if (mysql_stmt_prepare(stmt, statement, strlen(statement) )) {
- failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
- }
- int param_cnt = mysql_stmt_param_count(stmt);
- if (param_cnt != 11) {
- failure("Parameter count sanity check failed.");
- }
-
- memset(bind, 0, sizeof(bind));
-
- // 1st parameter: IPv4 address
- bind[0].buffer_type = MYSQL_TYPE_LONG;
- bind[0].buffer = (&addr);
- bind[0].is_null = 0;
- bind[0].length = 0;
-
- // 2nd parameter: Hardware address
- bind[1].buffer_type = MYSQL_TYPE_VARCHAR;
- bind[1].buffer = hwaddr;
- bind[1].buffer_length = hwaddr_len;
- bind[1].is_null = 0;
- bind[1].length = &hwaddr_len;
-
- // 3rd parameter: Client-id
- bind[2].buffer_type = MYSQL_TYPE_VARCHAR;
- bind[2].buffer = client_id;
- bind[2].buffer_length = client_id_len;
- bind[2].is_null = 0;
- bind[2].length = &client_id_len;
-
- // 4th parameter: valid-lifetime
- bind[3].buffer_type = MYSQL_TYPE_LONG;
- bind[3].buffer = (&valid_lft);
- bind[3].is_null = 0;
- bind[3].length = 0;
-
- // 5th parameter: recycle-time
- bind[4].buffer_type = MYSQL_TYPE_LONG;
- bind[4].buffer = (&recycle_time);
- bind[4].is_null = 0;
- bind[4].length = 0;
-
- // 6th parameter: cltt
- bind[5].buffer_type = MYSQL_TYPE_TIMESTAMP;
- bind[5].buffer = cltt;
- bind[2].buffer_length = cltt_len;
- bind[5].is_null = 0;
- bind[5].length = &cltt_len;
-
- // 7th parameter: pool-id
- bind[6].buffer_type = MYSQL_TYPE_LONG;
- bind[6].buffer = &pool_id;
- bind[6].is_null = 0;
- bind[6].length = 0;
-
- // 8th parameter: fixed
- bind[7].buffer_type = MYSQL_TYPE_TINY;
- bind[7].buffer = &fixed;
- bind[7].is_null = 0;
- bind[7].length = 0;
-
- // 9th parameter: hostname
- bind[8].buffer_type = MYSQL_TYPE_VARCHAR;
- bind[8].buffer = hostname;
- bind[8].buffer_length = strlen(hostname);
- bind[8].is_null = 0;
- bind[8].length = &hostname_len;
-
- // 10th parameter: fqdn_fwd
- bind[9].buffer_type = MYSQL_TYPE_TINY;
- bind[9].buffer = &fqdn_fwd;
- bind[9].is_null = 0;
- bind[9].length = 0;
-
- // 11th parameter: fqdn_rev
- bind[10].buffer_type = MYSQL_TYPE_TINY;
- bind[10].buffer = &fqdn_rev;
- bind[10].is_null = 0;
- bind[10].length = 0;
- }
-
- for (uint32_t i = 0; i < num_; i++) {
-
- sprintf(cltt, "2012-07-11 15:43:%02d", i % 60);
-
-
- addr++;
-
- if (!compiled_stmt_) {
- // the first address is 1.0.0.0.
- char query[2000], * end;
- strcpy(query, "INSERT INTO lease4(addr,hwaddr,client_id,"
- "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
- "fqdn_fwd,fqdn_rev) VALUES(");
- end = query + strlen(query);
- end += sprintf(end, "%u,\'", addr);
- end += mysql_real_escape_string(conn_, end, hwaddr, hwaddr_len);
- end += sprintf(end,"\',\'");
- end += mysql_real_escape_string(conn_, end, client_id, client_id_len);
- end += sprintf(end, "\',%d,%d,'%s',%d,%s,\'%s\',%s,%s);",
- valid_lft, recycle_time, cltt,
- pool_id, (fixed?"true":"false"), hostname,
- (fqdn_fwd?"true":"false"), (fqdn_rev?"true":"false"));
- // lease_id field is set automatically
- // options and comments fields are not set
-
- unsigned int len = end - query;
- if (mysql_real_query(conn_, query, len)) {
- // something failed.
- failure("INSERT query");
- }
- } else {
- // compiled statement
-
- if (mysql_stmt_bind_param(stmt, bind)) {
- failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
- }
-
- if (mysql_stmt_execute(stmt)) {
- failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
- }
-
- }
-
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- if (mysql_stmt_close(stmt)) {
- failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
- }
- }
-
- cout << endl;
-}
-
-void MySQL_uBenchmark::searchLease4Test() {
- if (!conn_) {
- throw "Not connected to MySQL server.";
- }
-
- cout << "RETRIEVE: ";
-
- uint32_t addr = 0;
-
- MYSQL_STMT * stmt = NULL;
- MYSQL_BIND bind[1]; // just a single element
- if (compiled_stmt_) {
- stmt = mysql_stmt_init(conn_);
- if (!stmt) {
- failure("Unable to create compiled statement");
- }
- const char * statement = "SELECT lease_id,addr,hwaddr,client_id,"
- "valid_lft, cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
- "FROM lease4 where addr=?";
- if (mysql_stmt_prepare(stmt, statement, strlen(statement))) {
- failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
- }
- int param_cnt = mysql_stmt_param_count(stmt);
- if (param_cnt != 1) {
- failure("Parameter count sanity check failed.");
- }
-
- memset(bind, 0, sizeof(bind));
-
- // 1st parameter: IPv4 address
- bind[0].buffer_type = MYSQL_TYPE_LONG;
- bind[0].buffer = (&addr);
- bind[0].is_null = 0;
- bind[0].length = 0;
- }
-
- for (uint32_t i = 0; i < num_; i++) {
-
- addr = BASE_ADDR4 + random() % int(num_ / hitratio_);
-
- if (!compiled_stmt_) {
- char query[512];
- sprintf(query, "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
- "cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
- "FROM lease4 where addr=%d", addr);
- mysql_real_query(conn_, query, strlen(query));
-
- MYSQL_RES * result = mysql_store_result(conn_);
-
- int num_rows = mysql_num_rows(result);
- int num_fields = mysql_num_fields(result);
-
- if ( (num_rows > 1) ) {
- stringstream tmp;
- tmp << "Search: DB returned " << num_rows << " leases for address "
- << hex << addr << dec;
- failure(tmp.str().c_str());
- }
-
- if (num_rows) {
- if (num_fields == 0) {
- failure("Query returned empty set");
- }
-
- MYSQL_ROW row = mysql_fetch_row(result);
-
- // pretend to do something with it
- if (row[0] == NULL) {
- failure("SELECT returned NULL data.");
- }
- mysql_free_result(result);
-
- if (verbose_) {
- cout << "."; // hit
- }
-
- } else {
- if (verbose_) {
- cout << "x"; // miss
- }
- }
- } else {
- // compiled statement
-
- if (mysql_stmt_bind_param(stmt, bind)) {
- failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
- }
-
- if (mysql_stmt_execute(stmt)) {
- failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
- }
-
- MYSQL_BIND response[11];
-
- size_t length[11];
- my_bool is_null[11];
- my_bool error[11];
-
- uint32_t lease_id;
- uint32_t lease_addr;
- char hwaddr[20];
- char client_id[128];
- uint32_t valid_lft; // We can use the same value for all leases
- MYSQL_TIME cltt;
- uint32_t pool_id;
- my_bool fixed;
- char hostname[255];
- my_bool fqdn_fwd;
- my_bool fqdn_rev;
-
- for (int j = 0; j < 11; j++) {
- response[j].is_null = &is_null[j];
- response[j].length = &length[j];
- response[j].error = &error[j];
- }
-
- // 1th parameter: lease_id
- response[0].buffer_type = MYSQL_TYPE_LONG;
- response[0].buffer = (&lease_id);
-
- // 2nd parameter: IPv4 address
- response[1].buffer_type = MYSQL_TYPE_LONG;
- response[1].buffer = (&lease_addr);
-
- // 3rd parameter: Hardware address
- response[2].buffer_type = MYSQL_TYPE_STRING;
- response[2].buffer = hwaddr;
- response[2].buffer_length = sizeof(hwaddr);
-
- // 4th parameter: Client-id
- response[3].buffer_type = MYSQL_TYPE_STRING;
- response[3].buffer = &client_id;
- response[3].buffer_length = sizeof(client_id);
-
- // 5th parameter: valid-lifetime
- response[4].buffer_type = MYSQL_TYPE_LONG;
- response[4].buffer = &valid_lft;
-
- // 6th parameter: cltt
- response[5].buffer_type = MYSQL_TYPE_TIMESTAMP;
- response[5].buffer = &cltt;
-
- // 7th parameter: pool-id
- response[6].buffer_type = MYSQL_TYPE_LONG;
- response[6].buffer = &pool_id;
-
- // 8th parameter: fixed
- response[7].buffer_type = MYSQL_TYPE_TINY;
- response[7].buffer = &fixed;
-
- // 9th parameter: hostname
- response[8].buffer_type = MYSQL_TYPE_STRING;
- response[8].buffer = &hostname;
-
- // 10th parameter: fqdn_fwd
- response[9].buffer_type = MYSQL_TYPE_TINY;
- response[9].buffer = &fqdn_fwd;
-
- // 11th parameter: fqdn_rev
- response[10].buffer_type = MYSQL_TYPE_TINY;
- response[10].buffer = &fqdn_rev;
-
- if (mysql_stmt_bind_result(stmt, response))
- {
- cout << "Error:" << mysql_stmt_error(stmt) << endl;
- failure("mysql_stmt_bind_result() failed");
- }
- int num_rows = 0;
-
- int result = mysql_stmt_fetch(stmt);
- switch (result) {
- case 0: {
- if (lease_addr != addr) {
- failure("Returned data is bogus!");
- }
- num_rows++;
- break;
- }
- case MYSQL_NO_DATA:
- {
- // that's ok. We randomized non-existing address
- break;
-
- }
- default: {
- stmt_failure(stmt, "RETRIEVE (mysql_stmt_fetch())");
- }
- }
-
- // we could call mysql_stmt_fetch again to check that there are no
- // other data for us. But there should be exactly one row of data
- // with specified address.
-
- if (num_rows) {
- if (verbose_) {
- cout << "."; // hit
- }
- } else {
- if (verbose_) {
- cout << "X"; // miss
- }
- }
-
- }
- }
-
- if (compiled_stmt_) {
- if (mysql_stmt_close(stmt)) {
- failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
- }
- }
-
- cout << endl;
-}
-
-void MySQL_uBenchmark::updateLease4Test() {
- if (!conn_) {
- throw "Not connected to MySQL server.";
- }
-
- cout << "UPDATE: ";
-
- uint32_t valid_lft = 1002; // just some dummy value
- char cltt[] = "now()";
- size_t cltt_len = strlen(cltt);
- uint32_t addr = 0;
-
- MYSQL_STMT * stmt = NULL;
- MYSQL_BIND bind[3];
- if (compiled_stmt_) {
- stmt = mysql_stmt_init(conn_);
- if (!stmt) {
- failure("Unable to create compiled statement");
- }
- const char * statement = "UPDATE lease4 SET valid_lft=?, cltt=? WHERE addr=?";
- if (mysql_stmt_prepare(stmt, statement, strlen(statement))) {
- failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
- }
- int param_cnt = mysql_stmt_param_count(stmt);
- if (param_cnt != 3) {
- failure("Parameter count sanity check failed.");
- }
-
- memset(bind, 0, sizeof(bind));
-
- // 1st parameter: valid lifetime
- bind[0].buffer_type = MYSQL_TYPE_LONG;
- bind[0].buffer = &valid_lft;
-
- // 2nd parameter: cltt
- bind[1].buffer_type = MYSQL_TYPE_STRING;
- bind[1].buffer = &cltt;
- bind[1].buffer_length = cltt_len;
-
- bind[2].buffer_type = MYSQL_TYPE_LONG;
- bind[2].buffer = &addr;
- }
-
-
- for (uint32_t i = 0; i < num_; i++) {
-
- addr = BASE_ADDR4 + random() % num_;
-
- if (!compiled_stmt_) {
- char query[128];
- sprintf(query, "UPDATE lease4 SET valid_lft=1002, cltt=now() WHERE addr=%d", addr);
- mysql_real_query(conn_, query, strlen(query));
-
- } else {
- // compiled statement
- if (mysql_stmt_bind_param(stmt, bind)) {
- failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
- }
-
- if (mysql_stmt_execute(stmt)) {
- failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
- }
- }
-
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- if (mysql_stmt_close(stmt)) {
- failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
- }
- }
-
- cout << endl;
-}
-
-void MySQL_uBenchmark::deleteLease4Test() {
- if (!conn_) {
- throw "Not connected to MySQL server.";
- }
-
- cout << "DELETE: ";
-
- uint32_t addr = 0;
-
- MYSQL_STMT * stmt = NULL;
- MYSQL_BIND bind[1]; // just a single element
- if (compiled_stmt_) {
-
- stmt = mysql_stmt_init(conn_);
- if (!stmt) {
- failure("Unable to create compiled statement, mysql_stmt_init() failed");
- }
-
- const char * statement = "DELETE FROM lease4 WHERE addr=?";
-
- if (mysql_stmt_prepare(stmt, statement, strlen(statement) )) {
- failure("Failed to prepare statement, mysql_stmt_prepare() returned non-zero");
- }
- int param_cnt = mysql_stmt_param_count(stmt);
- if (param_cnt != 1) {
- failure("Parameter count sanity check failed.");
- }
-
- memset(bind, 0, sizeof(bind));
-
- // 1st parameter: IPv4 address
- bind[0].buffer_type = MYSQL_TYPE_LONG;
- bind[0].buffer = (&addr);
- bind[0].is_null = 0;
- bind[0].length = 0;
- }
-
-
- for (uint32_t i = 0; i < num_; i++) {
-
- addr = BASE_ADDR4 + i;
-
- if (!compiled_stmt_) {
- char query[128];
- sprintf(query, "DELETE FROM lease4 WHERE addr=%d", addr);
- mysql_real_query(conn_, query, strlen(query));
- } else {
- // compiled statement
- if (mysql_stmt_bind_param(stmt, bind)) {
- failure("Failed to bind parameters: mysql_stmt_bind_param() returned non-zero");
- }
-
- if (mysql_stmt_execute(stmt)) {
- failure("Failed to execute statement: mysql_stmt_execute() returned non-zero");
- }
- }
-
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- if (mysql_stmt_close(stmt)) {
- failure("Failed to close compiled statement, mysql_stmt_close returned non-zero");
- }
- }
-
- cout << endl;
-}
-
-void MySQL_uBenchmark::printInfo() {
- cout << "MySQL client version is " << mysql_get_client_info() << endl;
-}
-
-
-int main(int argc, char * const argv[]) {
-
- const char* hostname ="localhost"; // -m (MySQL server)
- const char* user = "root"; // -u
- const char* passwd = "secret"; // -p
- const char* dbname = "kea"; // -f
- uint32_t num = 100; // -n
- bool sync = true; // -s
- bool verbose = true; // -v
-
- MySQL_uBenchmark bench(hostname, user, passwd, dbname, num, sync, verbose);
-
- bench.parseCmdline(argc, argv);
-
- int result = bench.run();
-
- return (result);
-}
diff --git a/tests/tools/dhcp-ubench/mysql_ubench.h b/tests/tools/dhcp-ubench/mysql_ubench.h
deleted file mode 100644
index be12fd6fd1..0000000000
--- a/tests/tools/dhcp-ubench/mysql_ubench.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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 <string>
-#include "benchmark.h"
-
-/// @brief MySQL micro-benchmark.
-///
-/// That is a specific backend implementation. See \ref uBenchmark class for
-/// detailed explanation of its operations. This class uses MySQL as database
-/// backend.
-class MySQL_uBenchmark: public uBenchmark {
-public:
-
- /// @brief The sole MySQL micro-benchmark constructor
- ///
- /// To avoid influence of network performance, it is highly recommended
- /// to run MySQL engine on the same host as benchmark. Thus hostname
- /// is likely to be "localhost". Make sure that the selected database
- /// is already created and that it follows expected schema. See mysql.schema
- /// and isc-dhcp-perf-guide.html for details.
- ///
- /// Synchronous operation means using InnDB, async is MyISAM.
- ///
- /// @param hostname Name of the host to connect to
- /// @param user usename used during MySQL connection
- /// @param pass password used during MySQL connection
- /// @param db name of the database to connect to
- /// @param num_iterations number of iterations for basic operations
- /// @param sync synchronous or asynchronous database writes
- /// @param verbose should extra information be logged?
- MySQL_uBenchmark(const std::string& hostname, const std::string& user,
- const std::string& pass, const std::string& db,
- uint32_t num_iterations, bool sync,
- bool verbose);
-
- /// @brief Prints MySQL version info.
- virtual void printInfo();
-
- /// @brief Opens connection to the MySQL database.
- virtual void connect();
-
- /// @brief Closes connection to the MySQL database.
- virtual void disconnect();
-
- /// @brief Creates new leases.
- ///
- /// See uBenchmark::createLease4Test() for detailed explanation.
- virtual void createLease4Test();
-
- /// @brief Searches for existing leases.
- ///
- /// See uBenchmark::searchLease4Test() for detailed explanation.
- virtual void searchLease4Test();
-
- /// @brief Updates existing leases.
- ///
- /// See uBenchmark::updateLease4Test() for detailed explanation.
- virtual void updateLease4Test();
-
- /// @brief Deletes existing leases.
- ///
- /// See uBenchmark::deleteLease4Test() for detailed explanation.
- virtual void deleteLease4Test();
-
-protected:
- /// @brief Used to report any database failures.
- ///
- /// Compared to its base version in uBenchmark class, this one logs additional
- /// MySQL specific information using mysql_errno() and mysql_error() functions.
- /// The outcome is the same: exception is thrown.
- ///
- /// @param operation brief description of the operation that caused error
- ///
- /// @sa stmt_failure()
- void failure(const char* operation);
-
- /// @brief Used to report compiled statement failures.
- ///
- /// Compared to its base version in uBenchmark class, this one logs additional
- /// MySQL specific information using mysql_stmt_errno() and mysql_stmt_error()
- /// functions that are used for compiled statements error reporting.
- ///
- /// @param stmt MySQL compiled statement structure
- /// @param operation brief description of the operation that caused error
- ///
- /// @sa failure()
- void stmt_failure(MYSQL_STMT * stmt, const char* operation);
-
-
- /// Handle to MySQL database connection.
- MYSQL* conn_;
-};
diff --git a/tests/tools/dhcp-ubench/performance-results-graph1.png b/tests/tools/dhcp-ubench/performance-results-graph1.png
deleted file mode 100644
index a173aa6a83..0000000000
--- a/tests/tools/dhcp-ubench/performance-results-graph1.png
+++ /dev/null
Binary files differ
diff --git a/tests/tools/dhcp-ubench/performance-results-graph2.png b/tests/tools/dhcp-ubench/performance-results-graph2.png
deleted file mode 100644
index b53263bf71..0000000000
--- a/tests/tools/dhcp-ubench/performance-results-graph2.png
+++ /dev/null
Binary files differ
diff --git a/tests/tools/dhcp-ubench/performance-results.ods b/tests/tools/dhcp-ubench/performance-results.ods
deleted file mode 100644
index b9c68bf93a..0000000000
--- a/tests/tools/dhcp-ubench/performance-results.ods
+++ /dev/null
Binary files differ
diff --git a/tests/tools/dhcp-ubench/sqlite.schema b/tests/tools/dhcp-ubench/sqlite.schema
deleted file mode 100644
index e0e6c56671..0000000000
--- a/tests/tools/dhcp-ubench/sqlite.schema
+++ /dev/null
@@ -1,85 +0,0 @@
-DROP TABLE lease4;
-DROP TABLE lease6;
-DROP TABLE host;
-
-CREATE TABLE lease4 (
-
- -- Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
- lease_id SERIAL,
- addr INT UNSIGNED UNIQUE,
-
- -- The largest hardware address is for Infiniband (20 bytes)
- hwaddr VARCHAR(20),
-
- -- The largest client-id is DUID in DHCPv6 - up to 128 bytes
- client_id VARCHAR(128),
-
- -- Expressed in seconds
- valid_lft INT,
-
- -- Expressed in seconds,
- recycle_time INT DEFAULT 0,
-
- cltt TIMESTAMP,
-
- pool_id int,
-
- fixed BOOL,
-
- -- DDNS stuff
- hostname VARCHAR(255),
- fqdn_fwd BOOL DEFAULT false,
- fqdn_rev BOOL DEFAULT false,
-
- options TEXT,
- comments TEXT
-);
-
-CREATE TABLE lease6 (
-
- -- Primary key (serial = BININT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE)
- lease_id SERIAL,
- addr CHAR(16) UNIQUE,
-
- -- The largest hardware address is for Infiniband (20 bytes)
- hwaddr VARCHAR(20),
-
- -- The largest client-id is DUID in DHCPv6 - up to 128 bytes
- client_id VARCHAR(128),
-
- iaid int unsigned,
-
- -- Used for IA_PD only (tinyint = 0..255)
- prefix_len TINYINT unsigned,
-
- -- Expressed in seconds
- preferred_lft INT,
-
- -- Expressed in seconds
- valid_lft INT,
-
- -- Expressed in seconds,
- recycle_time INT DEFAULT 0,
-
- cltt TIMESTAMP,
-
- pool_id int,
-
- fixed BOOL DEFAULT false,
-
- hostname VARCHAR(255),
- fqdn_fwd BOOL DEFAULT false,
- fqdn_rev BOOL DEFAULT false,
-
- options TEXT,
- comments TEXT
-);
-
-CREATE TABLE host (
- address BIGINT NULL,
- address6 BIGINT NULL,
- prefix6 BIGINT NULL,
- hostname VARCHAR(255),
- options TEXT,
- comments TEXT
-); \ No newline at end of file
diff --git a/tests/tools/dhcp-ubench/sqlite_ubench.cc b/tests/tools/dhcp-ubench/sqlite_ubench.cc
deleted file mode 100644
index 1018b2b337..0000000000
--- a/tests/tools/dhcp-ubench/sqlite_ubench.cc
+++ /dev/null
@@ -1,513 +0,0 @@
-// 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 <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sstream>
-#include <iostream>
-#include <sqlite3.h>
-#include "sqlite_ubench.h"
-
-using namespace std;
-
-SQLite_uBenchmark::SQLite_uBenchmark(const string& filename,
- uint32_t num_iterations,
- bool sync, bool verbose)
- :uBenchmark(num_iterations, filename, sync, verbose),
- db_(NULL) {
-
-}
-
-void SQLite_uBenchmark::connect() {
- int result = sqlite3_open(dbname_.c_str(), &db_);
- if (result != SQLITE_OK) {
- failure("Failed to open DB file");
- }
-
- result = sqlite3_exec(db_, "DELETE FROM lease4", NULL, NULL, NULL);
- if (result != SQLITE_OK) {
- failure("Failed to delete old entries");
- }
-
- if (sync_) {
- sqlite3_exec(db_, "PRAGMA synchronous = ON", NULL, NULL, NULL);
- } else {
- sqlite3_exec(db_, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
- }
-
- // see http://www.sqlite.org/pragma.html#pragma_journal_mode
- // for detailed explanation. Available modes: DELETE, TRUNCATE,
- // PERSIST, MEMORY, WAL, OFF
- sqlite3_exec(db_, "PRAGMA journal_mode = OFF", NULL, NULL, NULL);
-}
-
-void SQLite_uBenchmark::disconnect() {
- if (db_) {
- sqlite3_close(db_);
- db_ = NULL;
- } else {
- throw "Can't close SQLite connection: it was never open.";
- }
-}
-
-void SQLite_uBenchmark::createLease4Test() {
- if (!db_) {
- throw "SQLite connection is closed.";
- }
-
- uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
- const uint8_t hwaddr_len = 20; // Not a real field
- char hwaddr[hwaddr_len];
- const uint8_t client_id_len = 128;
- char client_id[client_id_len];
- uint32_t valid_lft = 1000; // We can use the same value for all leases
- uint32_t recycle_time = 0; // Not supported in any foresable future,
- // so keep this as 0
- char cltt[48]; // Timestamp
- uint32_t pool_id = 0; // Let's use pools 0-99
- bool fixed = false;
- string hostname("foo"); // Will generate it dynamically
- bool fqdn_fwd = true; // Let's pretend to do AAAA update
- bool fqdn_rev = true; // Let's pretend to do PTR update
-
- cout << "CREATE: ";
-
- for (uint8_t i = 0; i < hwaddr_len; i++) {
- hwaddr[i] = 65 + i;
- }
- hwaddr[19] = 0; // workaround
-
- for (uint8_t i = 0; i < client_id_len; i++) {
- client_id[i] = 33 + i;
- }
- client_id[6] = 'X'; // there's apostrophe here. It would confuse
- // query formatting, let's get rid of it
- client_id[127] = 0; // workaround
-
-
- sqlite3_stmt *stmt = NULL;
- if (compiled_stmt_) {
- char query[] = "INSERT INTO lease4(addr,hwaddr,client_id,"
- "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
- "fqdn_fwd,fqdn_rev) VALUES(?001,?002,?003,?004,?005,?006,?007,?008,?009,?010,?011);";
- int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
- if (result != SQLITE_OK) {
- failure("Failed to compile statement");
- }
- }
-
-
-
- for (uint32_t i = 0; i < num_; i++) {
-
- sprintf(cltt, "2012-07-11 15:43:%02d", i % 60);
-
- addr++;
- char* errorMsg = NULL;
-
- if (!compiled_stmt_) {
- // the first address is 1.0.0.0.
- char query[2000];
- /// @todo: Encode HWADDR and CLIENT-ID properly
- sprintf(query, "INSERT INTO lease4(addr,hwaddr,client_id,"
- "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
- "fqdn_fwd,fqdn_rev) VALUES(%u,'%s','%s',%d,%d,'%s',%d,'%s','%s','%s','%s');",
- addr, hwaddr, client_id, valid_lft, recycle_time,
- cltt, pool_id, (fixed?"true":"false"),
- hostname.c_str(), (fqdn_fwd?"true":"false"), (fqdn_rev?"true":"false"));
-
- int result = sqlite3_exec(db_, query, NULL, 0, &errorMsg);
-
- if (result != SQLITE_OK) {
- stringstream tmp;
- tmp << "INSERT error:" << errorMsg;
- failure(tmp.str().c_str());
- }
- } else {
- // compiled statement
- int result = sqlite3_bind_int(stmt, 1, addr);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 1");
- }
-
- result = sqlite3_bind_blob(stmt, 2, hwaddr, hwaddr_len, NULL);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_blob() for column 2");
- }
-
- result = sqlite3_bind_blob(stmt, 3, client_id, client_id_len, NULL);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_blob() for column 3");
- }
-
- if (sqlite3_bind_int(stmt, 4, valid_lft) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 4");
- }
-
- if (sqlite3_bind_int(stmt, 5, recycle_time) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 5");
- }
-
- if (sqlite3_bind_text(stmt, 6, cltt, strlen(cltt), NULL) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 6");
- }
-
- if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 7");
- }
-
- if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 7");
- }
-
- if (sqlite3_bind_int(stmt, 8, fixed) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 8");
- }
-
- if (sqlite3_bind_text(stmt, 9, hostname.c_str(), hostname.length(), NULL) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 9");
- }
-
- if (sqlite3_bind_int(stmt, 10, fqdn_fwd) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 10");
- }
-
- if (sqlite3_bind_int(stmt, 11, fqdn_rev) != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 11");
- }
-
- result = sqlite3_step(stmt);
-
- if (result != SQLITE_DONE) {
- failure("Failed to execute INSERT clause");
- }
-
- // let's reset the compiled statement, so it can be used in the
- // next iteration
- result = sqlite3_reset(stmt);
- if (result != SQLITE_OK) {
- failure("Failed to execute sqlite3_reset()");
- }
-
- }
-
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- int result = sqlite3_finalize(stmt);
- if (result != SQLITE_OK) {
- failure("sqlite3_finalize() failed");
- }
- }
-
- cout << endl;
-}
-
-static int search_callback(void *counter, int argc, char** argv,
- char** azColName){
-
- int* cnt = static_cast<int*>(counter);
- (*cnt)++;
-
- char buf[512];
-
- // retrieved lease can be accessed here
- for(int i = 0; i < argc; i++){
- // pretend we do something with returned lease
- if (argv[i]) {
- strncpy(buf, azColName[i], 512);
- strncpy(buf, argv[i], 512);
- }
-
- // Uncomment this to print out all contents
- // cout << azColName[i] << "=" << (argv[i] ? argv[i] : "NULL") << endl;
- }
-
- return (0);
-}
-
-void SQLite_uBenchmark::searchLease4Test() {
- if (!db_) {
- throw "SQLite connection is closed.";
- }
-
- cout << "RETRIEVE: ";
-
- sqlite3_stmt *stmt = NULL;
- if (compiled_stmt_) {
- const char query[] = "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
- "cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
- "FROM lease4 where addr=?1";
-
- int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
- if (result != SQLITE_OK) {
- failure("Failed to compile statement");
- }
- }
-
-
- for (uint32_t i = 0; i < num_; i++) {
-
- uint32_t addr = BASE_ADDR4 + random() % int(num_ / hitratio_);
-
- int cnt = 0;
-
- if (!compiled_stmt_) {
- char* errorMsg = NULL;
-
- char query[512];
- sprintf(query, "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
- "cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
- "FROM lease4 where addr=%d", addr);
- int result = sqlite3_exec(db_, query, search_callback, &cnt, &errorMsg);
- if (result != SQLITE_OK) {
- stringstream tmp;
- tmp << "SELECT failed: " << errorMsg;
- failure(tmp.str().c_str());
- }
- } else {
- // compiled statement
- int result = sqlite3_bind_int(stmt, 1, addr);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 1");
- }
-
- result = sqlite3_step(stmt);
- switch (result) {
- case SQLITE_ROW:
- {
- uint32_t lease_addr = sqlite3_column_int(stmt, 1);
- const void * lease_hwaddr = sqlite3_column_blob(stmt, 2);
- uint32_t lease_hwaddr_len = sqlite3_column_bytes(stmt, 2);
- const void * lease_clientid = sqlite3_column_blob(stmt, 3);
- uint32_t lease_clientid_len = sqlite3_column_bytes(stmt, 3);
- uint32_t lease_valid_lft = sqlite3_column_int(stmt, 4);
-
- // cltt
- const unsigned char *lease_cltt = sqlite3_column_text(stmt, 5);
-
- uint32_t lease_pool_id = sqlite3_column_int(stmt, 6);
- uint32_t lease_fixed = sqlite3_column_int(stmt, 7);
-
- const unsigned char *lease_hostname = sqlite3_column_text(stmt, 8);
-
- uint32_t lease_fqdn_fwd = sqlite3_column_int(stmt, 9);
- uint32_t lease_fqdn_rev = sqlite3_column_int(stmt, 10);
-
- if (lease_addr || lease_hwaddr || lease_hwaddr_len || lease_clientid ||
- lease_clientid_len || lease_valid_lft || lease_cltt || lease_pool_id ||
- lease_fixed || lease_hostname || lease_fqdn_fwd || lease_fqdn_rev) {
- // we don't need this information, we just want to obtain it to measure
- // the overhead. That strange if is only to quell compiler/cppcheck
- // warning about unused variables.
-
- cnt = 1;
- }
-
- cnt = 1; // there is at least one row
- break;
- }
- case SQLITE_DONE:
- cnt = 0; // there are no rows at all (i.e. no such lease)
- break;
- default:
- failure("Failed to execute SELECT clause");
- }
-
- // let's reset the compiled statement, so it can be used in the
- // next iteration
- result = sqlite3_reset(stmt);
- if (result != SQLITE_OK) {
- failure("Failed to execute sqlite3_reset()");
- }
- }
-
- if (verbose_) {
- cout << (cnt?".":"X");
- }
- }
-
- if (compiled_stmt_) {
- int result = sqlite3_finalize(stmt);
- if (result != SQLITE_OK) {
- failure("sqlite3_finalize() failed");
- }
- }
-
- cout << endl;
-}
-
-void SQLite_uBenchmark::updateLease4Test() {
- if (!db_) {
- throw "SQLite connection is closed.";
- }
-
- cout << "UPDATE: ";
-
- sqlite3_stmt *stmt = NULL;
- if (compiled_stmt_) {
- const char query[] = "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=?1";
-
- int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
- if (result != SQLITE_OK) {
- failure("Failed to compile statement");
- }
- }
-
- for (uint32_t i = 0; i < num_; i++) {
-
- uint32_t addr = BASE_ADDR4 + random() % num_;
-
- if (!compiled_stmt_) {
- char* errorMsg = NULL;
- char query[512];
- sprintf(query, "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=%d",
- addr);
-
- int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
- if (result != SQLITE_OK) {
- stringstream tmp;
- tmp << "UPDATE error:" << errorMsg;
- failure(tmp.str().c_str());
- }
- } else {
-
- int result = sqlite3_bind_int(stmt, 1, addr);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 1");
- }
-
- result = sqlite3_step(stmt);
- if (result != SQLITE_OK && result != SQLITE_DONE) {
- failure("Failed to execute sqlite3_step() for UPDATE");
- }
-
- // let's reset the compiled statement, so it can be used in the
- // next iteration
- result = sqlite3_reset(stmt);
- if (result != SQLITE_OK) {
- failure("Failed to execute sqlite3_reset()");
- }
-
- }
-
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- int result = sqlite3_finalize(stmt);
- if (result != SQLITE_OK) {
- failure("sqlite3_finalize() failed");
- }
- }
-
- cout << endl;
-}
-
-void SQLite_uBenchmark::deleteLease4Test() {
- if (!db_) {
- throw "SQLite connection is closed.";
- }
-
- cout << "DELETE: ";
-
- sqlite3_stmt *stmt = NULL;
- if (compiled_stmt_) {
- const char query[] = "DELETE FROM lease4 WHERE addr=?1";
-
- int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
- if (result != SQLITE_OK) {
- failure("Failed to compile statement");
- }
- }
-
- for (uint32_t i = 0; i < num_; i++) {
-
- uint32_t addr = BASE_ADDR4 + i;
- if (!compiled_stmt_) {
- char* errorMsg = NULL;
-
- char query[2000];
- sprintf(query, "DELETE FROM lease4 WHERE addr=%d", addr);
- int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
- if (result != SQLITE_OK) {
- stringstream tmp;
- tmp << "DELETE error:" << errorMsg;
- failure(tmp.str().c_str());
- }
- } else {
- // compiled statement
-
- int result = sqlite3_bind_int(stmt, 1, addr);
- if (result != SQLITE_OK) {
- failure("sqlite3_bind_int() for column 1");
- }
-
- result = sqlite3_step(stmt);
- if (result != SQLITE_OK && result != SQLITE_DONE) {
- failure("Failed to execute sqlite3_step() for UPDATE");
- }
-
- // let's reset the compiled statement, so it can be used in the
- // next iteration
- result = sqlite3_reset(stmt);
- if (result != SQLITE_OK) {
- failure("Failed to execute sqlite3_reset()");
- }
-
- }
- if (verbose_) {
- cout << ".";
- }
- }
-
- if (compiled_stmt_) {
- int result = sqlite3_finalize(stmt);
- if (result != SQLITE_OK) {
- failure("sqlite3_finalize() failed");
- }
- }
-
- cout << endl;
-}
-
-void SQLite_uBenchmark::printInfo() {
- cout << "SQLite version is " << sqlite3_libversion()
- << "sourceid version is " << sqlite3_sourceid() << endl;
-}
-
-
-
-int main(int argc, char* const argv[]) {
-
- const char* filename = "sqlite.db";
- uint32_t num = 100;
- bool sync = true;
- bool verbose = true;
-
- SQLite_uBenchmark bench(filename, num, sync, verbose);
-
- bench.parseCmdline(argc, argv);
-
- int result = bench.run();
-
- return (result);
-}
diff --git a/tests/tools/dhcp-ubench/sqlite_ubench.h b/tests/tools/dhcp-ubench/sqlite_ubench.h
deleted file mode 100644
index 366b50a860..0000000000
--- a/tests/tools/dhcp-ubench/sqlite_ubench.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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 <string>
-#include "benchmark.h"
-
-/// @brief SQLite benchmark
-///
-/// That is a specific backend implementation. See \ref uBenchmark class for
-/// detailed explanation of its operations. This class uses SQLite as DB backend.
-class SQLite_uBenchmark: public uBenchmark {
-public:
-
- /// @brief The sole SQL benchmark constructor
- ///
- /// DB file must be present and appropriate database schema must
- /// be used. See sqlite.schema script and isc-dhcp-perf-guide.html
- /// for details.
- ///
- /// sync flag affects "PRAGMA synchronous" to be ON or OFF.
- ///
- /// @param filename name of the SQLite DB file. Must be present.
- /// @param num_iterations number of iterations of basic lease operations
- /// @param sync should the operations be synchronous or not?
- /// @param verbose would you like extra details be logged?
- SQLite_uBenchmark(const std::string& filename,
- uint32_t num_iterations,
- bool sync, bool verbose);
-
- /// @brief Prints SQLite version info.
- virtual void printInfo();
-
- /// @brief Opens connection to the SQLite database.
- virtual void connect();
-
- /// @brief Closes connection to the SQLite database.
- virtual void disconnect();
-
- /// @brief Creates new leases.
- ///
- /// See uBenchmark::createLease4Test() for detailed explanation.
- virtual void createLease4Test();
-
- /// @brief Searches for existing leases.
- ///
- /// See uBenchmark::searchLease4Test() for detailed explanation.
- virtual void searchLease4Test();
-
- /// @brief Updates existing leases.
- ///
- /// See uBenchmark::updateLease4Test() for detailed explanation.
- virtual void updateLease4Test();
-
- /// @brief Deletes existing leases.
- ///
- /// See uBenchmark::deleteLease4Test() for detailed explanation.
- virtual void deleteLease4Test();
-
-protected:
-
- /// Handle to SQLite database connection.
- sqlite3 *db_;
-};