Last active
December 18, 2015 09:09
-
-
Save malcom/5759223 to your computer and use it in GitHub Desktop.
TestBenchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Test::Benchmark example | |
// http://gist.github.com/malcom/5759223 | |
#include "testbenchm.hpp" | |
#include <iostream> | |
#include <iomanip> | |
#include <memory> | |
#include <random> | |
#include <algorithm> // std::generate_n | |
#include <functional> // std::hash | |
// Hash function based of implementation available at | |
// http://www.partow.net/programming/hashfunctions/ | |
uint32_t RSHash(const char* data, size_t len) { | |
uint32_t b = 378551; | |
uint32_t a = 63689; | |
uint32_t hash = 0; | |
for (size_t i = 0; i < len; i++) { | |
hash = hash * a + data[i]; | |
a = a * b; | |
} | |
return hash; | |
} | |
uint32_t JSHash(const char* data, size_t len) { | |
uint32_t hash = 1315423911; | |
for (size_t i = 0; i < len; i++) | |
hash ^= ((hash << 5) + data[i] + (hash >> 2)); | |
return hash; | |
} | |
uint32_t ELFHash(const char* data, size_t len) { | |
uint32_t hash = 0; | |
uint32_t x = 0; | |
for (size_t i = 0; i < len; i++) { | |
hash = (hash << 4) + data[i]; | |
x = hash & 0xF0000000L; | |
if (x != 0) | |
hash ^= (x >> 24); | |
hash &= ~x; | |
} | |
return hash; | |
} | |
uint32_t DJBHash(const char* data, size_t len) { | |
uint32_t hash = 5381; | |
for (size_t i = 0; i < len; i++) | |
hash = ((hash << 5) + hash) + data[i]; | |
return hash; | |
} | |
uint32_t STLHash(const char* data, size_t len) { | |
uint32_t hash = 0; | |
std::hash<char> hasher; | |
for (size_t i = 0; i < len; ++i) | |
hash = hash ^ hasher(data[i]); | |
return hash; | |
} | |
int main(int argc, char* argv[]) { | |
const int Length = 256 * 1024; | |
const int Count = 1000; | |
typedef std::chrono::microseconds Time; | |
std::unique_ptr<char[]> data(new char[Length]); | |
// randomize data | |
{ | |
static const char alphanum[] = | |
"0123456789" | |
"!@#$%^&*" | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
"abcdefghijklmnopqrstuvwxyz"; | |
std::default_random_engine rng; | |
std::uniform_int_distribution<> dist(0, sizeof(alphanum) -1); | |
char* out = std::generate_n(data.get(), Length - 1, [&](){ return alphanum[dist(rng)]; }); | |
*out = '\0'; | |
} | |
//typedef uint32_t (*hash_func_t)(const char*, size_t); | |
typedef decltype(&STLHash) hash_func_t; | |
struct function_t { | |
hash_func_t func; | |
const char* name; | |
}; | |
const function_t functions[] = { | |
{ RSHash, "RS-Hash Function" }, | |
{ JSHash, "JS-Hash Function" }, | |
{ ELFHash, "ELF-Hash Function" }, | |
{ DJBHash, "DJB-Hash Function" }, | |
{ STLHash, "STL-Hash Function" }, | |
}; | |
namespace TB = Test::Benchmark; | |
std::cout << "Sample hash operations perfomance test\n\n"; | |
std::cout << "Count: " << Count << ", Buffer length: " << Length << "\n\n"; | |
std::cout << " name avg min max\n"; | |
for (auto& f : functions) { | |
TB::Result::Data<Time> result; | |
TB::Run<Time>( [&]() { f.func(data.get(), Length); }, Count, result); | |
std::cout | |
<< std::left | |
<< std::setw(20) << f.name << " " | |
<< std::right | |
<< std::setw(8) << TB::Result::Mean<typename Time::rep>(result) << " " | |
<< std::setw(8) << TB::Result::Min<typename Time::rep>(result) << " " | |
<< std::setw(8) << TB::Result::Max<typename Time::rep>(result) << " " | |
<< std::endl; | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TestBenchmark | |
// Marcin 'Malcom' Malich <me@malcom.pl> | |
// http://blog.malcom.pl/2013/06/11/prosty-benchmark-testow/ | |
// MIT License | |
#ifndef TEST_BENCHMARK_HPP | |
#define TEST_BENCHMARK_HPP | |
#include <vector> | |
#include <iterator> | |
#include <algorithm> | |
#include <numeric> | |
#include <chrono> | |
namespace Test { | |
namespace Benchmark { | |
namespace Result { | |
#ifdef _MSC_VER | |
// VS2k12 not support 'Alias templates' | |
template<typename Time> | |
struct Data : public std::vector<typename Time::rep> {}; | |
#else | |
template<typename Time> using Data = std::vector<typename Time::rep>; | |
#endif | |
template<typename T, typename D> | |
T Count(const D& data) { | |
return std::distance(std::begin(data), std::end(data)); | |
} | |
template<typename T, typename D> | |
T Min(const D& data) { | |
return *std::min_element(std::begin(data), std::end(data)); | |
} | |
template<typename T, typename D> | |
T Max(const D& data) { | |
return *std::max_element(std::begin(data), std::end(data)); | |
} | |
template<typename T, typename D> | |
T Mean(const D& data) { | |
auto n = std::distance(std::begin(data), std::end(data)); | |
return std::accumulate(std::begin(data), std::end(data), T()) / n; | |
} | |
} // namespace Result | |
template<typename Time, typename F> | |
void Run(F func, int count, Result::Data<Time>& data) { | |
for (int i = 0; i < count; i++) { | |
auto t1 = std::chrono::high_resolution_clock::now(); | |
func(); | |
auto t2 = std::chrono::high_resolution_clock::now(); | |
std::back_inserter(data) = std::chrono::duration_cast<Time>(t2 - t1).count(); | |
} | |
} | |
} // namespace Benchmark | |
} // namespace Test | |
#endif // TEST_BENCHMARK_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment