diff options
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 "—" > -<!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 < 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 > 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>> <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>> <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>> <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>> <userinput>./sqlite_ubench</userinput></screen> - or - <screen>> <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<>). 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>> <userinput>./memfile_ubench</userinput></screen> - or - <screen>> <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 Binary files differdeleted file mode 100644 index a173aa6a83..0000000000 --- a/tests/tools/dhcp-ubench/performance-results-graph1.png +++ /dev/null diff --git a/tests/tools/dhcp-ubench/performance-results-graph2.png b/tests/tools/dhcp-ubench/performance-results-graph2.png Binary files differdeleted file mode 100644 index b53263bf71..0000000000 --- a/tests/tools/dhcp-ubench/performance-results-graph2.png +++ /dev/null diff --git a/tests/tools/dhcp-ubench/performance-results.ods b/tests/tools/dhcp-ubench/performance-results.ods Binary files differdeleted file mode 100644 index b9c68bf93a..0000000000 --- a/tests/tools/dhcp-ubench/performance-results.ods +++ /dev/null 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_; -}; |