forked from MassiveAtoms/hashmap-bench
working code
This commit is contained in:
151
src/includes/aggregate_tests.h
Normal file
151
src/includes/aggregate_tests.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#ifndef ATESTS_H
|
||||
#define ATESTS_H
|
||||
#include <string>
|
||||
#include "./tests.h"
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
std::vector<int> sizes = {
|
||||
50000, 100000, 150000, 200000, 250000, 300000, 350000, 400000, 500000,
|
||||
600000, 700000, 800000, 900000, 1000000,
|
||||
2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000, 9000000, 10000000,
|
||||
15000000, 20000000, 25000000, 30000000, 35000000, 40000000, 45000000, 50000000
|
||||
};
|
||||
|
||||
|
||||
// to print type info
|
||||
|
||||
template <typename T>
|
||||
constexpr auto type_name()
|
||||
{
|
||||
std::string_view name, prefix, suffix;
|
||||
#ifdef __clang__
|
||||
name = __PRETTY_FUNCTION__;
|
||||
prefix = "auto type_name() [T = ";
|
||||
suffix = "]";
|
||||
#elif defined(__GNUC__)
|
||||
name = __PRETTY_FUNCTION__;
|
||||
prefix = "constexpr auto type_name() [with T = ";
|
||||
suffix = "]";
|
||||
#elif defined(_MSC_VER)
|
||||
name = __FUNCSIG__;
|
||||
prefix = "auto __cdecl type_name<";
|
||||
suffix = ">(void)";
|
||||
#endif
|
||||
name.remove_prefix(prefix.size());
|
||||
name.remove_suffix(suffix.size());
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
std::basic_string_view<char> name(T var){
|
||||
return type_name<decltype(var)>();
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
int int_test(T map, int repeats=30){
|
||||
std::ofstream output{"results.csv", std::ios_base::app};
|
||||
// insert int tests
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "insert_int, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
std::cout << size << ", ";
|
||||
float result = insert_int_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
// lookup int
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "lookup_int, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = lookup_int_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
// unsuccesful lookup
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "nolookup_int, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = nolookup_int_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
// deletion
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "delete_int, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = delete_int_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
int string_test(T map, int repeats=30){
|
||||
std::ofstream output{"results.csv", std::ios_base::app};
|
||||
// insert int tests
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "insert_string, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = insert_string_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
// lookup int
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "lookup_string, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = lookup_string_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
// unsuccesful lookup
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "nolookup_string, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = nolookup_string_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
// deletion
|
||||
for (int i = 0; i < repeats; ++i){
|
||||
std::string resultline = "delete_string, '" + std::string{name(map)} + "', ";
|
||||
for (auto size: sizes){
|
||||
float result = delete_string_test(size, T{}).count();
|
||||
resultline += std::to_string(result);
|
||||
resultline += ", ";
|
||||
}
|
||||
output << resultline << "\n";
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
24
src/includes/generator.h
Normal file
24
src/includes/generator.h
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
#ifndef GENERATOR_H
|
||||
#define GENERATOR_H
|
||||
|
||||
|
||||
|
||||
|
||||
#include <random>
|
||||
#include <string>
|
||||
static std::mt19937 generator(INT32_MAX - 2020);
|
||||
static std::uniform_int_distribution<int> gen_insert_int(1, INT32_MAX * 0.875);
|
||||
static std::uniform_int_distribution<int> gen_noninsert_int(INT32_MAX * 0.875, INT32_MAX);
|
||||
static std::uniform_int_distribution<int> gen_char(33, 123);
|
||||
|
||||
|
||||
int gen_int();
|
||||
int gen_unsuccesfull_int();
|
||||
std::string gen_string();
|
||||
std::string gen_unsuccesfull_string();
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* GENERATOR_H */
|
310
src/includes/tests.h
Normal file
310
src/includes/tests.h
Normal file
@@ -0,0 +1,310 @@
|
||||
|
||||
#ifndef TESTS_H
|
||||
#define TESTS_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <chrono>
|
||||
|
||||
#include "./generator.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
|
||||
template <class T>
|
||||
nanoseconds insert_int_test(int size, T testmap){
|
||||
// init hashmap, insert size - 10k items
|
||||
testmap.reserve(size);
|
||||
for (int i = 0; i < size - 10000; ++i){
|
||||
int a = gen_int();
|
||||
testmap.insert({a,a});
|
||||
}
|
||||
// generate 10k keys
|
||||
std::vector<int> keys(10000);
|
||||
std::generate(keys.begin(), keys.end(), gen_int);
|
||||
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : keys){
|
||||
if (i == -1) { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// measure insert time
|
||||
time_point<steady_clock> start_insert_test = steady_clock::now();
|
||||
for (auto i : keys){
|
||||
testmap.insert({i,i});
|
||||
}
|
||||
time_point<steady_clock> end_insert_test = steady_clock::now();
|
||||
|
||||
// time per insert
|
||||
auto duration = duration_cast<nanoseconds>(end_insert_test - start_insert_test) - vector_time ;
|
||||
return duration / 10000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
nanoseconds insert_string_test(int size, T testmap){
|
||||
// init hashmap, insert size - 10k items
|
||||
testmap.reserve(size);
|
||||
for (int i = 0; i < size - 10000; ++i){
|
||||
std::string temp = gen_string();
|
||||
testmap.insert({temp,temp});
|
||||
}
|
||||
// generate 10k keys
|
||||
std::vector<std::string> keys(10000);
|
||||
std::generate(keys.begin(), keys.end(), gen_string);
|
||||
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : keys){
|
||||
if (i == "a") { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// measure insert time
|
||||
time_point<steady_clock> start_insert_test = steady_clock::now();
|
||||
for (auto i : keys){
|
||||
testmap.insert({i,i});
|
||||
}
|
||||
time_point<steady_clock> end_insert_test = steady_clock::now();
|
||||
|
||||
// time per insert
|
||||
auto duration = duration_cast<nanoseconds>(end_insert_test - start_insert_test) - vector_time ;
|
||||
return duration / 10000;
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
nanoseconds lookup_int_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<int> sample_inserted;
|
||||
sample_inserted.reserve(10000);
|
||||
|
||||
|
||||
{
|
||||
std::vector<int> keys(size);
|
||||
std::generate(keys.begin(), keys.end(), gen_int);
|
||||
std::sample(keys.begin(), keys.end(), std::back_inserter(sample_inserted) , 10000, generator);
|
||||
for (auto i : keys){
|
||||
testmap.insert({i, i});
|
||||
}
|
||||
}
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
if (i == -1) { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
if (testmap[i] == -1){
|
||||
std::cout << "SOMETHUNG IS WRONG!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
nanoseconds lookup_string_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<std::string> sample_inserted(1000);
|
||||
// sample_inserted.reserve(10000);
|
||||
{
|
||||
std::vector<std::string> keys(size);
|
||||
std::generate(keys.begin(), keys.end(), gen_string);
|
||||
std::sample(keys.begin(), keys.end(), std::back_inserter(sample_inserted) , 10000, generator);
|
||||
for (auto i : keys){
|
||||
testmap.insert({i, i});
|
||||
}
|
||||
}
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
if (i == "a") { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
|
||||
for (auto i : sample_inserted){
|
||||
if (testmap[i] == "a"){
|
||||
std::cout << "SOMETHUNG IS WRONG!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
nanoseconds nolookup_int_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<int>lookup_keys(10000);
|
||||
std::generate(lookup_keys.begin(), lookup_keys.end(), gen_unsuccesfull_int);
|
||||
for (int i = 0; i < size; ++i){
|
||||
int temp = gen_int();
|
||||
testmap.insert({temp, temp});
|
||||
}
|
||||
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : lookup_keys){
|
||||
if (i == -1) { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
for (auto i : lookup_keys){
|
||||
if (testmap[i] == -1){
|
||||
std::cout << "SOMETHUNG IS WRONG!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
nanoseconds nolookup_string_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<std::string>lookup_keys(10000);
|
||||
std::generate(lookup_keys.begin(), lookup_keys.end(), gen_unsuccesfull_string);
|
||||
for (int i = 0; i < size; ++i){
|
||||
std::string temp = gen_string();
|
||||
testmap.insert({temp, temp});
|
||||
}
|
||||
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : lookup_keys){
|
||||
if (i == "a") { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
for (auto i : lookup_keys){
|
||||
if (testmap[i] == "a"){
|
||||
std::cout << "SOMETHUNG IS WRONG!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
nanoseconds delete_int_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<int> sample_inserted;
|
||||
sample_inserted.reserve(10000);
|
||||
|
||||
{
|
||||
std::vector<int> keys(size);
|
||||
std::generate(keys.begin(), keys.end(), gen_int);
|
||||
std::sample(keys.begin(), keys.end(), std::back_inserter(sample_inserted) , 10000, generator);
|
||||
for (auto i : keys){
|
||||
testmap.insert({i, i});
|
||||
}
|
||||
}
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
if (i == -1) { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
testmap.erase(i);
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class T>
|
||||
nanoseconds delete_string_test(int size, T testmap){
|
||||
// reserve, get random 10k keys that are inserted, insert keys
|
||||
testmap.reserve(size);
|
||||
std::vector<std::string> sample_inserted;
|
||||
sample_inserted.reserve(10000);
|
||||
|
||||
{
|
||||
std::vector<std::string> keys(size);
|
||||
std::generate(keys.begin(), keys.end(), gen_string);
|
||||
std::sample(keys.begin(), keys.end(), std::back_inserter(sample_inserted) , 10000, generator);
|
||||
for (auto i : keys){
|
||||
testmap.insert({i, i});
|
||||
}
|
||||
}
|
||||
// benchmark vector access time
|
||||
time_point<steady_clock> start_v_access = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
if (i == "a") { // it'll never be, this is just anti optimisation
|
||||
std::cout << "Something is very wrong!";
|
||||
}
|
||||
}
|
||||
time_point<steady_clock> end_v_access = steady_clock::now();
|
||||
auto vector_time = duration_cast<nanoseconds>(end_v_access - start_v_access);
|
||||
|
||||
// benchmark access time of hashmap
|
||||
time_point<steady_clock> start_benchmark = steady_clock::now();
|
||||
for (auto i : sample_inserted){
|
||||
testmap.erase(i);
|
||||
}
|
||||
time_point<steady_clock> end_benchmark = steady_clock::now();
|
||||
auto duration = duration_cast<nanoseconds>(end_benchmark - start_benchmark) - vector_time;
|
||||
return duration / 10000;
|
||||
}
|
||||
|
||||
#endif /* TESTS_H */
|
Reference in New Issue
Block a user