Commit a25ec56d authored by Marcin Siodelski's avatar Marcin Siodelski

[3736] Removed dhcp-ubench and folders.

parent bfce8a98
......@@ -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 \
......
......@@ -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], [
......
SUBDIRS = tools
\ No newline at end of file
# 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 $<
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
// 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;
}
// 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
This diff is collapsed.
// 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()) {