test refactoring - work in progress

This commit is contained in:
Marko Budiselic 2016-12-22 15:51:16 +01:00
parent 55a62f9640
commit c22cdf929d
36 changed files with 861 additions and 707 deletions

View File

@ -1,46 +0,0 @@
#pragma once
#include <list>
#include "threading/sync/lockable.hpp"
#include "threading/sync/spinlock.hpp"
template <typename value_type, typename lock_type = SpinLock>
class LinkedList : public Lockable<lock_type>
{
public:
std::size_t size() const
{
auto guard = this->acquire_unique();
return data.size();
}
void push_front(const value_type &value)
{
auto guard = this->acquire_unique();
data.push_front(value);
}
void push_front(value_type &&value)
{
auto guard = this->acquire_unique();
data.push_front(std::forward<value_type>(value));
}
void pop_front()
{
auto guard = this->acquire_unique();
data.pop_front();
}
// value_type& as return value
// would not be concurrent
value_type front()
{
auto guard = this->acquire_unique();
return data.front();
}
private:
std::list<value_type> data;
};

View File

@ -8,7 +8,9 @@
#include "logging/default.hpp" #include "logging/default.hpp"
/** @class Timer /**
* @class Timer
*
* @brief The timer contains counter and handler. * @brief The timer contains counter and handler.
* *
* With every clock interval the counter should be decresed for * With every clock interval the counter should be decresed for
@ -48,7 +50,9 @@ struct Timer
* the process method. * the process method.
*/ */
/** @class TimerSet /**
* @class TimerSet
*
* @brief Trivial timer container implementation. * @brief Trivial timer container implementation.
* *
* Internal data stucture for storage of timers is std::set. So, the * Internal data stucture for storage of timers is std::set. So, the
@ -70,6 +74,11 @@ public:
timers.erase(timer); timers.erase(timer);
} }
uint64_t size() const
{
return timers.size();
}
void process() void process()
{ {
for (auto it = timers.begin(); it != timers.end(); ) { for (auto it = timers.begin(); it != timers.end(); ) {
@ -87,10 +96,17 @@ private:
std::set<std::shared_ptr<Timer>> timers; std::set<std::shared_ptr<Timer>> timers;
}; };
/** @class TimerScheduler /**
* @class TimerScheduler
*
* @brief TimerScheduler is a manager class and its responsibility is to * @brief TimerScheduler is a manager class and its responsibility is to
* take care of the time and call the timer_container process method in the * take care of the time and call the timer_container process method in the
* appropriate time. * appropriate time.
*
* @tparam timer_container_type implements a strategy how the timers
* are processed
* @tparam delta_time_type type of a time distance between two events
* @tparam delta_time granularity between the two events, default value is 1
*/ */
template < template <
typename timer_container_type, typename timer_container_type,
@ -99,19 +115,47 @@ template <
> class TimerScheduler > class TimerScheduler
{ {
public: public:
/**
* Adds a timer.
*
* @param timer shared pointer to the timer object \ref Timer
*/
void add(Timer::sptr timer) void add(Timer::sptr timer)
{ {
timer_container.add(timer); timer_container.add(timer);
} }
/**
* Removes a timer.
*
* @param timer shared pointer to the timer object \ref Timer
*/
void remove(Timer::sptr timer) void remove(Timer::sptr timer)
{ {
timer_container.remove(timer); timer_container.remove(timer);
} }
/**
* Provides the number of pending timers. The exact number has to be
* provided by a timer_container.
*
* @return uint64_t the number of pending timers.
*/
uint64_t size() const
{
return timer_container.size();
}
/**
* Runs a separate thread which responsibility is to run the process method
* at the appropriate time (every delta_time from the beginning of
* processing.
*/
void run() void run()
{ {
is_running.store(true); is_running.store(true);
run_thread = std::thread([this]() { run_thread = std::thread([this]() {
while (is_running.load()) { while (is_running.load()) {
std::this_thread::sleep_for(delta_time_type(delta_time)); std::this_thread::sleep_for(delta_time_type(delta_time));
@ -121,11 +165,17 @@ public:
}); });
} }
/**
* Stops the whole processing.
*/
void stop() void stop()
{ {
is_running.store(false); is_running.store(false);
} }
/**
* Joins the processing thread.
*/
~TimerScheduler() ~TimerScheduler()
{ {
run_thread.join(); run_thread.join();

View File

@ -6,6 +6,8 @@ enable_testing()
include_directories(${catch_source_dir}/include) include_directories(${catch_source_dir}/include)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test_results)
# copy test data # copy test data
file(COPY ${CMAKE_SOURCE_DIR}/tests/data file(COPY ${CMAKE_SOURCE_DIR}/tests/data
DESTINATION ${CMAKE_BINARY_DIR}/tests) DESTINATION ${CMAKE_BINARY_DIR}/tests)

View File

@ -1,6 +1,8 @@
#include <random> #include <random>
#include <thread> #include <thread>
#include "benchmark/benchmark_api.h"
#include "data_structures/bloom/bloom_filter.hpp" #include "data_structures/bloom/bloom_filter.hpp"
#include "logging/default.hpp" #include "logging/default.hpp"
#include "logging/streams/stdout.hpp" #include "logging/streams/stdout.hpp"
@ -8,43 +10,40 @@
#include "utils/hashing/fnv64.hpp" #include "utils/hashing/fnv64.hpp"
#include "utils/random/generator.h" #include "utils/random/generator.h"
#include "benchmark/benchmark_api.h"
using utils::random::StringGenerator; using utils::random::StringGenerator;
using StringHashFunction = std::function<uint64_t(const std::string&)>; using StringHashFunction = std::function<uint64_t(const std::string &)>;
template <class Type, int Size> template <class Type, int Size>
static void TestBloom(benchmark::State& state, BloomFilter<Type, Size>* static void TestBloom(benchmark::State &state, BloomFilter<Type, Size> *bloom,
bloom, const std::vector<Type>& elements) { const std::vector<Type> &elements)
while(state.KeepRunning()) { {
while (state.KeepRunning())
{
for (int start = 0; start < state.range(0); start++) for (int start = 0; start < state.range(0); start++)
if (start % 2) bloom->contains(elements[start]); if (start % 2)
else bloom->insert(elements[start]); bloom->contains(elements[start]);
else
bloom->insert(elements[start]);
} }
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
} }
auto BM_Bloom = [](benchmark::State& state, auto* bloom, const auto& elements) { auto BM_Bloom = [](benchmark::State &state, auto *bloom, const auto &elements) {
TestBloom(state, bloom, elements); TestBloom(state, bloom, elements);
}; };
void parse_args(int argc, char** argv) {} int main(int argc, char **argv)
{
int main(int argc, char** argv) {
logging::init_async(); logging::init_async();
logging::log->pipe(std::make_unique<Stdout>()); logging::log->pipe(std::make_unique<Stdout>());
parse_args(argc, argv);
StringGenerator generator(4); StringGenerator generator(4);
auto elements = utils::random::generate_vector(generator, 1 << 16); auto elements = utils::random::generate_vector(generator, 1 << 16);
StringHashFunction hash1 = fnv64<std::string>; StringHashFunction hash1 = fnv64<std::string>;
StringHashFunction hash2 = fnv1a64<std::string>; StringHashFunction hash2 = fnv1a64<std::string>;
std::vector<StringHashFunction> funcs = { std::vector<StringHashFunction> funcs = {hash1, hash2};
hash1, hash2
};
BloomFilter<std::string, 128> bloom(funcs); BloomFilter<std::string, 128> bloom(funcs);

View File

@ -27,7 +27,7 @@
using utils::random::NumberGenerator; using utils::random::NumberGenerator;
using utils::random::PairGenerator; using utils::random::PairGenerator;
using utils::random::StringGenerator; using utils::random::StringGenerator;
using StringHashFunction = std::function<uint64_t(const std::string&)>; using StringHashFunction = std::function<uint64_t(const std::string &)>;
using IntegerGenerator = NumberGenerator<std::uniform_int_distribution<int>, using IntegerGenerator = NumberGenerator<std::uniform_int_distribution<int>,
std::default_random_engine, int>; std::default_random_engine, int>;
@ -40,10 +40,14 @@ int THREADS, RANGE_START, RANGE_END, STRING_LENGTH;
ConcurrentMap Insertion Benchmark Test ConcurrentMap Insertion Benchmark Test
*/ */
template <class K, class V, class F> template <class K, class V, class F>
static void InsertValue(benchmark::State& state, ConcurrentBloomMap<K, V, F>* map, static void InsertValue(benchmark::State &state,
const std::vector<std::pair<K, V>>& elements) { ConcurrentBloomMap<K, V, F> *map,
while (state.KeepRunning()) { const std::vector<std::pair<K, V>> &elements)
for (int start = 0; start < state.range(0); start++) { {
while (state.KeepRunning())
{
for (int start = 0; start < state.range(0); start++)
{
map->insert(elements[start].first, elements[start].second); map->insert(elements[start].first, elements[start].second);
} }
} }
@ -54,21 +58,25 @@ static void InsertValue(benchmark::State& state, ConcurrentBloomMap<K, V, F>* ma
ConcurrentMap Contains Benchmark Test ConcurrentMap Contains Benchmark Test
*/ */
template <class K, class V, class F> template <class K, class V, class F>
static void ContainsValue(benchmark::State& state, ConcurrentBloomMap<K, V, F>* map, static void ContainsValue(benchmark::State &state,
const std::vector<std::pair<K, V>> elements) { ConcurrentBloomMap<K, V, F> *map,
while (state.KeepRunning()) { const std::vector<std::pair<K, V>> elements)
for (int start = 0; start < state.range(0); start++) { {
while (state.KeepRunning())
{
for (int start = 0; start < state.range(0); start++)
{
map->contains(elements[start].first); map->contains(elements[start].first);
} }
} }
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
} }
auto BM_InsertValue = [](benchmark::State& state, auto* map, auto& elements) { auto BM_InsertValue = [](benchmark::State &state, auto *map, auto &elements) {
InsertValue(state, map, elements); InsertValue(state, map, elements);
}; };
auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) { auto BM_ContainsValue = [](benchmark::State &state, auto *map, auto elements) {
ContainsValue(state, map, elements); ContainsValue(state, map, elements);
}; };
@ -88,7 +96,8 @@ auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) {
* Random String lenght * Random String lenght
-string-length number -string-length number
*/ */
void parse_arguments(int argc, char** argv) { void parse_arguments(int argc, char **argv)
{
REGISTER_ARGS(argc, argv); REGISTER_ARGS(argc, argv);
RANGE_START = GET_ARG("-start", "0").get_int(); RANGE_START = GET_ARG("-start", "0").get_int();
@ -101,7 +110,8 @@ void parse_arguments(int argc, char** argv) {
ProgramArguments::instance().get_arg("-string-length", "128").get_int(); ProgramArguments::instance().get_arg("-string-length", "128").get_int();
} }
int main(int argc, char** argv) { int main(int argc, char **argv)
{
logging::init_async(); logging::init_async();
logging::log->pipe(std::make_unique<Stdout>()); logging::log->pipe(std::make_unique<Stdout>());
@ -129,23 +139,20 @@ int main(int argc, char** argv) {
StringHashFunction hash1 = fnv64<std::string>; StringHashFunction hash1 = fnv64<std::string>;
StringHashFunction hash2 = fnv1a64<std::string>; StringHashFunction hash2 = fnv1a64<std::string>;
std::vector<StringHashFunction> funcs = { std::vector<StringHashFunction> funcs = {hash1, hash2};
hash1, hash2
};
BloomFilter<std::string, 128> bloom_filter_(funcs); BloomFilter<std::string, 128> bloom_filter_(funcs);
// maps used for testing // maps used for testing
//ConcurrentBloomMap<int, int> ii_map; // ConcurrentBloomMap<int, int> ii_map;
//ConcurrentBloomMap<int, std::string> is_map; // ConcurrentBloomMap<int, std::string> is_map;
using Filter = BloomFilter<std::string, 128>; using Filter = BloomFilter<std::string, 128>;
ConcurrentBloomMap<std::string, int, Filter > si_map(bloom_filter_); ConcurrentBloomMap<std::string, int, Filter> si_map(bloom_filter_);
ConcurrentBloomMap<std::string, std::string, Filter> ConcurrentBloomMap<std::string, std::string, Filter> ss_map(bloom_filter_);
ss_map(bloom_filter_);
// random elements for testing // random elements for testing
//auto ii_elems = utils::random::generate_vector(piig, MAX_ELEMENTS); // auto ii_elems = utils::random::generate_vector(piig, MAX_ELEMENTS);
//auto is_elems = utils::random::generate_vector(pisg, MAX_ELEMENTS); // auto is_elems = utils::random::generate_vector(pisg, MAX_ELEMENTS);
auto si_elems = utils::random::generate_vector(psig, MAX_ELEMENTS); auto si_elems = utils::random::generate_vector(psig, MAX_ELEMENTS);
auto ss_elems = utils::random::generate_vector(pssg, MAX_ELEMENTS); auto ss_elems = utils::random::generate_vector(pssg, MAX_ELEMENTS);

View File

@ -37,11 +37,14 @@ int THREADS, RANGE_START, RANGE_END, STRING_LENGTH;
ConcurrentMap Insertion Benchmark Test ConcurrentMap Insertion Benchmark Test
*/ */
template <class K, class V> template <class K, class V>
static void InsertValue(benchmark::State& state, ConcurrentMap<K, V>* map, static void InsertValue(benchmark::State &state, ConcurrentMap<K, V> *map,
const std::vector<std::pair<K, V>>& elements) { const std::vector<std::pair<K, V>> &elements)
while (state.KeepRunning()) { {
while (state.KeepRunning())
{
auto accessor = map->access(); auto accessor = map->access();
for (int start = 0; start < state.range(0); start++) { for (int start = 0; start < state.range(0); start++)
{
accessor.insert(elements[start].first, elements[start].second); accessor.insert(elements[start].first, elements[start].second);
} }
} }
@ -52,11 +55,14 @@ static void InsertValue(benchmark::State& state, ConcurrentMap<K, V>* map,
ConcurrentMap Deletion Benchmark Test ConcurrentMap Deletion Benchmark Test
*/ */
template <class K, class V> template <class K, class V>
static void DeleteValue(benchmark::State& state, ConcurrentMap<K, V>* map, static void DeleteValue(benchmark::State &state, ConcurrentMap<K, V> *map,
const std::vector<std::pair<K, V>> elements) { const std::vector<std::pair<K, V>> elements)
while (state.KeepRunning()) { {
while (state.KeepRunning())
{
auto accessor = map->access(); auto accessor = map->access();
for (int start = 0; start < state.range(0); start++) { for (int start = 0; start < state.range(0); start++)
{
accessor.remove(elements[start].first); accessor.remove(elements[start].first);
} }
} }
@ -67,26 +73,29 @@ static void DeleteValue(benchmark::State& state, ConcurrentMap<K, V>* map,
ConcurrentMap Contains Benchmark Test ConcurrentMap Contains Benchmark Test
*/ */
template <class K, class V> template <class K, class V>
static void ContainsValue(benchmark::State& state, ConcurrentMap<K, V>* map, static void ContainsValue(benchmark::State &state, ConcurrentMap<K, V> *map,
const std::vector<std::pair<K, V>> elements) { const std::vector<std::pair<K, V>> elements)
while (state.KeepRunning()) { {
while (state.KeepRunning())
{
auto accessor = map->access(); auto accessor = map->access();
for (int start = 0; start < state.range(0); start++) { for (int start = 0; start < state.range(0); start++)
{
accessor.contains(elements[start].first); accessor.contains(elements[start].first);
} }
} }
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
} }
auto BM_InsertValue = [](benchmark::State& state, auto* map, auto& elements) { auto BM_InsertValue = [](benchmark::State &state, auto *map, auto &elements) {
InsertValue(state, map, elements); InsertValue(state, map, elements);
}; };
auto BM_DeleteValue = [](benchmark::State& state, auto* map, auto elements) { auto BM_DeleteValue = [](benchmark::State &state, auto *map, auto elements) {
DeleteValue(state, map, elements); DeleteValue(state, map, elements);
}; };
auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) { auto BM_ContainsValue = [](benchmark::State &state, auto *map, auto elements) {
ContainsValue(state, map, elements); ContainsValue(state, map, elements);
}; };
@ -106,7 +115,8 @@ auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) {
* Random String lenght * Random String lenght
-string-length number -string-length number
*/ */
void parse_arguments(int argc, char** argv) { void parse_arguments(int argc, char **argv)
{
REGISTER_ARGS(argc, argv); REGISTER_ARGS(argc, argv);
RANGE_START = GET_ARG("-start", "0").get_int(); RANGE_START = GET_ARG("-start", "0").get_int();
@ -119,7 +129,8 @@ void parse_arguments(int argc, char** argv) {
ProgramArguments::instance().get_arg("-string-length", "128").get_int(); ProgramArguments::instance().get_arg("-string-length", "128").get_int();
} }
int main(int argc, char** argv) { int main(int argc, char **argv)
{
logging::init_async(); logging::init_async();
logging::log->pipe(std::make_unique<Stdout>()); logging::log->pipe(std::make_unique<Stdout>());
@ -159,8 +170,8 @@ int main(int argc, char** argv) {
/* insertion Tests */ /* insertion Tests */
benchmark::RegisterBenchmark("InsertValue[Int, Int]", BM_InsertValue, &ii_map, benchmark::RegisterBenchmark("InsertValue[Int, Int]", BM_InsertValue,
ii_elems) &ii_map, ii_elems)
->RangeMultiplier(MULTIPLIER) ->RangeMultiplier(MULTIPLIER)
->Range(1, MAX_ELEMENTS) ->Range(1, MAX_ELEMENTS)
->Complexity(benchmark::oN) ->Complexity(benchmark::oN)
@ -219,8 +230,8 @@ int main(int argc, char** argv) {
// Deletion Banchamark Tests // Deletion Banchamark Tests
benchmark::RegisterBenchmark("DeleteValue[Int, Int]", BM_DeleteValue, &ii_map, benchmark::RegisterBenchmark("DeleteValue[Int, Int]", BM_DeleteValue,
ii_elems) &ii_map, ii_elems)
->RangeMultiplier(MULTIPLIER) ->RangeMultiplier(MULTIPLIER)
->Range(1, MAX_ELEMENTS) ->Range(1, MAX_ELEMENTS)
->Complexity(benchmark::oN) ->Complexity(benchmark::oN)

View File

@ -28,20 +28,29 @@ int THREADS, INSERT_PERC, DELETE_PERC, CONTAINS_PERC, RANGE_START, RANGE_END;
// ConcurrentMap Becnhmark Test using percentages for Insert, Delete, Find // ConcurrentMap Becnhmark Test using percentages for Insert, Delete, Find
template <class K, class V> template <class K, class V>
static void Rape(benchmark::State& state, ConcurrentMap<int, int>* map, static void Rape(benchmark::State &state, ConcurrentMap<int, int> *map,
const std::vector<std::pair<K, V>>& elements) { const std::vector<std::pair<K, V>> &elements)
{
int number_of_elements = state.range(0); int number_of_elements = state.range(0);
while (state.KeepRunning()) { while (state.KeepRunning())
{
auto accessor = map->access(); auto accessor = map->access();
for (int start = 0; start < state.range(0); start++) { for (int start = 0; start < state.range(0); start++)
float current_percentage = (float)start / (float)number_of_elements * 100; {
if (current_percentage < (float)INSERT_PERC) { float current_percentage =
(float)start / (float)number_of_elements * 100;
if (current_percentage < (float)INSERT_PERC)
{
accessor.insert(elements[start].first, elements[start].second); accessor.insert(elements[start].first, elements[start].second);
} else if (current_percentage < (float)CONTAINS_PERC + INSERT_PERC) { }
else if (current_percentage < (float)CONTAINS_PERC + INSERT_PERC)
{
accessor.contains(elements[start].first); accessor.contains(elements[start].first);
} else { }
else
{
accessor.remove(elements[start].first); accessor.remove(elements[start].first);
} }
} }
@ -50,7 +59,7 @@ static void Rape(benchmark::State& state, ConcurrentMap<int, int>* map,
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
} }
auto BM_Rape = [](benchmark::State& state, auto* map, auto& elements) { auto BM_Rape = [](benchmark::State &state, auto *map, auto &elements) {
Rape(state, map, elements); Rape(state, map, elements);
}; };
@ -76,14 +85,16 @@ auto BM_Rape = [](benchmark::State& state, auto* map, auto& elements) {
* Number of threads * Number of threads
-threads number -threads number
*/ */
void parse_arguments(int argc, char** argv) { void parse_arguments(int argc, char **argv)
{
REGISTER_ARGS(argc, argv); REGISTER_ARGS(argc, argv);
INSERT_PERC = GET_ARG("-insert", "50").get_int(); INSERT_PERC = GET_ARG("-insert", "50").get_int();
DELETE_PERC = GET_ARG("-delete", "20").get_int(); DELETE_PERC = GET_ARG("-delete", "20").get_int();
CONTAINS_PERC = GET_ARG("-find", "30").get_int(); CONTAINS_PERC = GET_ARG("-find", "30").get_int();
if (INSERT_PERC + DELETE_PERC + CONTAINS_PERC != 100) { if (INSERT_PERC + DELETE_PERC + CONTAINS_PERC != 100)
{
std::cout << "Invalid percentage" << std::endl; std::cout << "Invalid percentage" << std::endl;
std::cout << "Percentage must sum to 100" << std::endl; std::cout << "Percentage must sum to 100" << std::endl;
exit(-1); exit(-1);
@ -97,7 +108,8 @@ void parse_arguments(int argc, char** argv) {
(int)std::thread::hardware_concurrency()); (int)std::thread::hardware_concurrency());
} }
int main(int argc, char** argv) { int main(int argc, char **argv)
{
logging::init_async(); logging::init_async();
logging::log->pipe(std::make_unique<Stdout>()); logging::log->pipe(std::make_unique<Stdout>());

View File

@ -1,21 +1,24 @@
#include "logging/default.hpp" #include "logging/default.hpp"
#include "logging/streams/stdout.hpp" #include "logging/streams/stdout.hpp"
#include "utils/time/timer.hpp"
#include "query/preprocesor.hpp" #include "query/preprocesor.hpp"
#include "utils/time/timer.hpp"
#include "benchmark/benchmark_api.h" #include "benchmark/benchmark_api.h"
#include "yaml-cpp/yaml.h" #include "yaml-cpp/yaml.h"
auto BM_Strip = [](benchmark::State& state, auto& function, std::string query) { auto BM_Strip = [](benchmark::State &state, auto &function, std::string query) {
while (state.KeepRunning()) { while (state.KeepRunning())
for (int start = 0; start < state.range(0); start++) { {
for (int start = 0; start < state.range(0); start++)
{
function(query); function(query);
} }
} }
state.SetComplexityN(state.range(0)); state.SetComplexityN(state.range(0));
}; };
int main(int argc, char** argv) { int main(int argc, char **argv)
{
logging::init_async(); logging::init_async();
logging::log->pipe(std::make_unique<Stdout>()); logging::log->pipe(std::make_unique<Stdout>());
@ -24,17 +27,17 @@ int main(int argc, char** argv) {
QueryPreprocessor processor; QueryPreprocessor processor;
using std::placeholders::_1; using std::placeholders::_1;
std::function<QueryStripped(const std::string& query)> preprocess = std::function<QueryStripped(const std::string &query)> preprocess =
std::bind(&QueryPreprocessor::preprocess, &processor, _1); std::bind(&QueryPreprocessor::preprocess, &processor, _1);
auto tests = dataset["benchmark_queries"].as<std::vector<std::string>>(); auto tests = dataset["benchmark_queries"].as<std::vector<std::string>>();
for (auto& test : tests) { for (auto &test : tests)
auto* benchmark = {
benchmark::RegisterBenchmark(test.c_str(), BM_Strip, preprocess, test) auto *benchmark = benchmark::RegisterBenchmark(test.c_str(), BM_Strip,
preprocess, test)
->RangeMultiplier(2) ->RangeMultiplier(2)
->Range(1, 8 << 10) ->Range(1, 8 << 10)
->Complexity(benchmark::oN); ->Complexity(benchmark::oN);
;
} }
benchmark::Initialize(&argc, argv); benchmark::Initialize(&argc, argv);

View File

@ -26,6 +26,8 @@ foreach(test_cpp ${test_type_cpps})
set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${exec_name}) set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${exec_name})
# link libraries # link libraries
# gtest
target_link_libraries(${target_name} gtest gtest_main)
# threads (cross-platform) # threads (cross-platform)
target_link_libraries(${target_name} Threads::Threads) target_link_libraries(${target_name} Threads::Threads)
# memgraph lib # memgraph lib

View File

@ -302,6 +302,7 @@ void memory_check(size_t no_threads, std::function<void()> f)
permanent_assert(true, "Memory leak"); permanent_assert(true, "Memory leak");
} }
// TODO: move this inside logging/default
// Initializes loging faccilityes // Initializes loging faccilityes
void init_log() void init_log()
{ {

View File

@ -8,7 +8,7 @@ constexpr size_t max_number = 10;
constexpr size_t no_find_per_change = 2; constexpr size_t no_find_per_change = 2;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// This test simulates behavior of transactions. // This test simulates behavior of a transactions.
// Each thread makes a series of finds interleaved with method which change. // Each thread makes a series of finds interleaved with method which change.
// Exact ratio of finds per change and insert per delete can be regulated with // Exact ratio of finds per change and insert per delete can be regulated with
// no_find_per_change and no_insert_for_one_delete. // no_find_per_change and no_insert_for_one_delete.

View File

@ -7,25 +7,33 @@ constexpr size_t no_slots = 1e4;
constexpr size_t key_range = no_slots * THREADS_NO * bit_part_len; constexpr size_t key_range = no_slots * THREADS_NO * bit_part_len;
constexpr size_t no_sets_per_clear = 2; constexpr size_t no_sets_per_clear = 2;
// TODO: document the test
int main() int main()
{ {
DynamicBitset<> db; DynamicBitset<> db;
auto seted = auto seted =
collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) { collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) {
auto rand = rand_gen(no_slots); auto rand = rand_gen(no_slots);
auto clear_op = rand_gen_bool(no_sets_per_clear); auto clear_op = rand_gen_bool(no_sets_per_clear);
std::vector<bool> set(key_range); std::vector<bool> set(key_range);
for (size_t i = 0; i < op_per_thread; i++) { for (size_t i = 0; i < op_per_thread; i++)
{
size_t num = size_t num =
rand() * THREADS_NO * bit_part_len + index * bit_part_len; rand() * THREADS_NO * bit_part_len + index * bit_part_len;
if (clear_op()) { if (clear_op())
{
db.clear(num, bit_part_len); db.clear(num, bit_part_len);
for (int j = 0; j < bit_part_len; j++) { for (int j = 0; j < bit_part_len; j++)
{
set[num + j] = false; set[num + j] = false;
} }
} else { }
else
{
db.set(num, bit_part_len); db.set(num, bit_part_len);
for (int j = 0; j < bit_part_len; j++) for (int j = 0; j < bit_part_len; j++)
set[num + j] = true; set[num + j] = true;

View File

@ -6,16 +6,20 @@ constexpr size_t up_border_bit_set_pow2 = 3;
constexpr size_t key_range = constexpr size_t key_range =
op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2; op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2;
// TODO: document the test
int main() int main()
{ {
DynamicBitset<> db; DynamicBitset<> db;
auto seted = auto seted =
collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) { collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) {
auto rand = rand_gen(key_range); auto rand = rand_gen(key_range);
auto rand_len = rand_gen(up_border_bit_set_pow2); auto rand_len = rand_gen(up_border_bit_set_pow2);
std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2)); std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2));
for (size_t i = 0; i < op_per_thread; i++) { for (size_t i = 0; i < op_per_thread; i++)
{
auto len = 1 << rand_len(); auto len = 1 << rand_len();
size_t num = (rand() / len) * len; size_t num = (rand() / len) * len;
db.set(num, len); db.set(num, len);
@ -32,10 +36,12 @@ int main()
auto rand_len = rand_gen(up_border_bit_set_pow2); auto rand_len = rand_gen(up_border_bit_set_pow2);
std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2)); std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2));
for (size_t i = 0; i < op_per_thread; i++) { for (size_t i = 0; i < op_per_thread; i++)
{
auto len = 1 << rand_len(); auto len = 1 << rand_len();
size_t num = (rand() / len) * len; size_t num = (rand() / len) * len;
for (int j = 0; j < len; j++) { for (int j = 0; j < len; j++)
{
set[num + j] = set[num + j] | db.at(num + j); set[num + j] = set[num + j] | db.at(num + j);
} }
db.clear(num, len); db.clear(num, len);
@ -44,7 +50,8 @@ int main()
return set; return set;
})); }));
for (size_t i = 0; i < seted.size(); i++) { for (size_t i = 0; i < seted.size(); i++)
{
seted[i] = seted[i] & (!cleared[i]); seted[i] = seted[i] & (!cleared[i]);
} }

View File

@ -4,14 +4,18 @@ constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t op_per_thread = 1e5; constexpr size_t op_per_thread = 1e5;
constexpr size_t key_range = op_per_thread * THREADS_NO * 3; constexpr size_t key_range = op_per_thread * THREADS_NO * 3;
// TODO: document the test
int main() int main()
{ {
DynamicBitset<> db; DynamicBitset<> db;
auto set = collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) { auto set = collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) {
auto rand = rand_gen(key_range); auto rand = rand_gen(key_range);
std::vector<bool> set(key_range); std::vector<bool> set(key_range);
for (size_t i = 0; i < op_per_thread; i++) { for (size_t i = 0; i < op_per_thread; i++)
{
size_t num = rand(); size_t num = rand();
db.set(num); db.set(num);
set[num] = true; set[num] = true;

View File

@ -6,15 +6,19 @@ constexpr size_t up_border_bit_set_pow2 = 3;
constexpr size_t key_range = constexpr size_t key_range =
op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2; op_per_thread * THREADS_NO * (1 << up_border_bit_set_pow2) * 2;
// TODO: document the test
int main() int main()
{ {
DynamicBitset<> db; DynamicBitset<> db;
auto set = collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) { auto set = collect_set(run<std::vector<bool>>(THREADS_NO, [&](auto index) {
auto rand = rand_gen(key_range); auto rand = rand_gen(key_range);
auto rand_len = rand_gen(up_border_bit_set_pow2); auto rand_len = rand_gen(up_border_bit_set_pow2);
std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2)); std::vector<bool> set(key_range + (1 << up_border_bit_set_pow2));
for (size_t i = 0; i < op_per_thread; i++) { for (size_t i = 0; i < op_per_thread; i++)
{
auto len = 1 << rand_len(); auto len = 1 << rand_len();
size_t num = (rand() / len) * len; size_t num = (rand() / len) * len;
db.set(num, len); db.set(num, len);

View File

@ -1,62 +0,0 @@
#include <cassert>
#include <iostream>
#include <thread>
#include "common.h"
#include "data_structures/linked_list.hpp"
using std::cout;
using std::endl;
template <typename list_type>
void test_concurrent_list_access(list_type &list, std::size_t size)
{
// test concurrent access
for (int i = 0; i < 1000000; ++i) {
std::thread t1([&list] {
list.push_front(1);
list.pop_front();
});
std::thread t2([&list] {
list.push_front(2);
list.pop_front();
});
t1.join();
t2.join();
assert(list.size() == size);
}
}
int main()
{
init_log();
LinkedList<int> list;
// push & pop operations
list.push_front(10);
list.push_front(20);
auto a = list.front();
assert(a == 20);
list.pop_front();
a = list.front();
assert(a == 10);
list.pop_front();
assert(list.size() == 0);
// concurrent test
LinkedList<int> concurrent_list;
concurrent_list.push_front(1);
concurrent_list.push_front(1);
std::list<int> no_concurrent_list;
no_concurrent_list.push_front(1);
no_concurrent_list.push_front(1);
test_concurrent_list_access(concurrent_list, 2);
// test_concurrent_list_access(no_concurrent_list, 2);
return 0;
}

View File

@ -5,11 +5,14 @@ constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elems_per_thread = 100000; constexpr size_t elems_per_thread = 100000;
constexpr size_t key_range = elems_per_thread * THREADS_NO * 2; constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// TODO: document the test
// This test checks insert_unique method under pressure. // This test checks insert_unique method under pressure.
// Test checks for missing data and changed/overwriten data. // Test checks for missing data and changed/overwriten data.
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;
@ -21,7 +24,8 @@ int main()
auto inserter = auto inserter =
insert_try<size_t, size_t, map_t>(acc, downcount, owned); insert_try<size_t, size_t, map_t>(acc, downcount, owned);
do { do
{
inserter(rand(), index); inserter(rand(), index);
} while (downcount > 0); } while (downcount > 0);
@ -30,7 +34,8 @@ int main()
}); });
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (auto &owned : collect(futures)) { for (auto &owned : collect(futures))
{
check_present_same<map_t>(accessor, owned); check_present_same<map_t>(accessor, owned);
} }

View File

@ -4,6 +4,8 @@ constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elems_per_thread = 100000; constexpr size_t elems_per_thread = 100000;
constexpr size_t key_range = elems_per_thread * THREADS_NO * 2; constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
// TODO: document the test
// This test checks insert_unique method under pressure. // This test checks insert_unique method under pressure.
// Threads will try to insert keys in the same order. // Threads will try to insert keys in the same order.
// This will force threads to compete intensly with each other. // This will force threads to compete intensly with each other.
@ -11,6 +13,7 @@ constexpr size_t key_range = elems_per_thread * THREADS_NO * 2;
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;
@ -22,7 +25,8 @@ int main()
auto inserter = auto inserter =
insert_try<size_t, size_t, map_t>(acc, downcount, owned); insert_try<size_t, size_t, map_t>(acc, downcount, owned);
for (int i = 0; downcount > 0; i++) { for (int i = 0; downcount > 0; i++)
{
inserter(i, index); inserter(i, index);
} }
@ -31,7 +35,8 @@ int main()
}); });
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (auto &owned : collect(futures)) { for (auto &owned : collect(futures))
{
check_present_same<map_t>(accessor, owned); check_present_same<map_t>(accessor, owned);
} }

View File

@ -3,19 +3,24 @@
constexpr size_t THREADS_NO = std::min(max_no_threads, 8); constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elems_per_thread = 1e5; constexpr size_t elems_per_thread = 1e5;
// TODO: document the test
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [&] { memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads; ds::static_array<std::thread, THREADS_NO> threads;
map_t skiplist; map_t skiplist;
// put THREADS_NO * elems_per_thread items to the skiplist // put THREADS_NO * elems_per_thread items to the skiplist
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) { for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i)
{
threads[thread_i] = std::thread( threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) { [&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) { for (size_t elem_i = start; elem_i < end; ++elem_i)
{
accessor.insert(elem_i, elem_i); accessor.insert(elem_i, elem_i);
} }
}, },
@ -23,7 +28,8 @@ int main()
thread_i * elems_per_thread + elems_per_thread); thread_i * elems_per_thread + elems_per_thread);
} }
// wait all threads // wait all threads
for (auto &thread : threads) { for (auto &thread : threads)
{
thread.join(); thread.join();
} }
@ -34,11 +40,13 @@ int main()
"all elements in skiplist"); "all elements in skiplist");
} }
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) { for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i)
{
threads[thread_i] = std::thread( threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) { [&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) { for (size_t elem_i = start; elem_i < end; ++elem_i)
{
permanent_assert(accessor.remove(elem_i) == true, ""); permanent_assert(accessor.remove(elem_i) == true, "");
} }
}, },
@ -46,7 +54,8 @@ int main()
thread_i * elems_per_thread + elems_per_thread); thread_i * elems_per_thread + elems_per_thread);
} }
// // wait all threads // // wait all threads
for (auto &thread : threads) { for (auto &thread : threads)
{
thread.join(); thread.join();
} }
@ -62,7 +71,8 @@ int main()
{ {
size_t iterator_counter = 0; size_t iterator_counter = 0;
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (auto elem : accessor) { for (auto elem : accessor)
{
++iterator_counter; ++iterator_counter;
cout << elem.first << " "; cout << elem.first << " ";
} }

View File

@ -1,13 +1,16 @@
#include "common.h" #include "common.h"
constexpr size_t THREADS_NO = std::min(max_no_threads, 8); constexpr size_t THREADS_NO = std::min(max_no_threads, 8);
constexpr size_t elements = 2e6; constexpr size_t elements = 2e6;
// Test for simple memory leaks /**
* Put elements number of elements in the skiplist per each thread and see
* is there any memory leak
*/
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;

View File

@ -3,20 +3,28 @@
constexpr size_t THREADS_NO = std::min(max_no_threads, 1); constexpr size_t THREADS_NO = std::min(max_no_threads, 1);
constexpr size_t elems_per_thread = 16e5; constexpr size_t elems_per_thread = 16e5;
// Known memory leak at 1,600,000 elements. // TODO: Memory leak at 1,600,000 elements (Kruno wrote this here but
// the memory_check method had invalid implementation)
// 1. implement valid memory_check
// 2. analyse this code
// 3. fix the memory leak
// 4. write proper test
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [&] { memory_check(THREADS_NO, [&] {
ds::static_array<std::thread, THREADS_NO> threads; ds::static_array<std::thread, THREADS_NO> threads;
map_t skiplist; map_t skiplist;
// put THREADS_NO * elems_per_thread items to the skiplist // put THREADS_NO * elems_per_thread items to the skiplist
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) { for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i)
{
threads[thread_i] = std::thread( threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) { [&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) { for (size_t elem_i = start; elem_i < end; ++elem_i)
{
accessor.insert(elem_i, elem_i); accessor.insert(elem_i, elem_i);
} }
}, },
@ -24,7 +32,8 @@ int main()
thread_i * elems_per_thread + elems_per_thread); thread_i * elems_per_thread + elems_per_thread);
} }
// wait all threads // wait all threads
for (auto &thread : threads) { for (auto &thread : threads)
{
thread.join(); thread.join();
} }
@ -35,11 +44,13 @@ int main()
"all elements in skiplist"); "all elements in skiplist");
} }
for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i) { for (size_t thread_i = 0; thread_i < THREADS_NO; ++thread_i)
{
threads[thread_i] = std::thread( threads[thread_i] = std::thread(
[&skiplist](size_t start, size_t end) { [&skiplist](size_t start, size_t end) {
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (size_t elem_i = start; elem_i < end; ++elem_i) { for (size_t elem_i = start; elem_i < end; ++elem_i)
{
permanent_assert(accessor.remove(elem_i) == true, ""); permanent_assert(accessor.remove(elem_i) == true, "");
} }
}, },
@ -47,7 +58,8 @@ int main()
thread_i * elems_per_thread + elems_per_thread); thread_i * elems_per_thread + elems_per_thread);
} }
// // wait all threads // // wait all threads
for (auto &thread : threads) { for (auto &thread : threads)
{
thread.join(); thread.join();
} }
@ -63,7 +75,8 @@ int main()
{ {
size_t iterator_counter = 0; size_t iterator_counter = 0;
auto accessor = skiplist.access(); auto accessor = skiplist.access();
for (auto elem : accessor) { for (auto elem : accessor)
{
++iterator_counter; ++iterator_counter;
cout << elem.first << " "; cout << elem.first << " ";
} }

View File

@ -7,13 +7,16 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// This test checks MultiIterator from multimap. /**
// Each thread removes random data. So removes are joint. * This test checks MultiIterator from multimap.
// Calls of remove method are interleaved with insert calls which always * Each thread removes random data. So removes are joint.
// succeed. * Calls of remove method are interleaved with insert calls which always
* succeed.
*/
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
multimap_t skiplist; multimap_t skiplist;

View File

@ -7,14 +7,16 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// This test checks MultiIterator remove method. /**
// Each thread removes random data. So removes are joint and scattered on same * This test checks MultiIterator remove method.
// key values. * Each thread removes random data. So removes are joint and scattered on same
// Calls of remove method are interleaved with insert calls which always * key values. Calls of remove method are interleaved with insert calls which
// succeed. * always succeed.
*/
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
multimap_t skiplist; multimap_t skiplist;
@ -26,23 +28,30 @@ int main()
std::vector<long long> set(key_range, 0); std::vector<long long> set(key_range, 0);
long long sum = 0; long long sum = 0;
do { do
{
size_t num = rand(); size_t num = rand();
auto data = rand() % max_number; auto data = rand() % max_number;
if (rand_op()) { if (rand_op())
{
int len = 0; int len = 0;
for (auto it = acc.find_multi(num); it.has_value(); for (auto it = acc.find_multi(num); it.has_value();
it++) { it++)
{
len++; len++;
} }
if (len > 0) { if (len > 0)
{
int pos = rand() % len; int pos = rand() % len;
for (auto it = acc.find_multi(num); it.has_value(); for (auto it = acc.find_multi(num); it.has_value();
it++) { it++)
if (pos == 0) { {
if (pos == 0)
{
auto data_r = it->second; auto data_r = it->second;
if (it.remove()) { if (it.remove())
{
downcount--; downcount--;
set[num]--; set[num]--;
sum -= data_r; sum -= data_r;
@ -55,7 +64,9 @@ int main()
pos--; pos--;
} }
} }
} else { }
else
{
acc.insert(num, data); acc.insert(num, data);
downcount--; downcount--;
set[num]++; set[num]++;
@ -68,9 +79,11 @@ int main()
long set[key_range] = {0}; long set[key_range] = {0};
long long sums = 0; long long sums = 0;
for (auto &data : collect(futures)) { for (auto &data : collect(futures))
{
sums += data.second.first; sums += data.second.first;
for (int i = 0; i < key_range; i++) { for (int i = 0; i < key_range; i++)
{
set[i] += data.second.second[i]; set[i] += data.second.second[i];
} }
} }
@ -78,7 +91,8 @@ int main()
auto accessor = skiplist.access(); auto accessor = skiplist.access();
check_multi_iterator(accessor, key_range, set); check_multi_iterator(accessor, key_range, set);
for (auto &e : accessor) { for (auto &e : accessor)
{
set[e.first]--; set[e.first]--;
sums -= e.second; sums -= e.second;
} }

View File

@ -7,15 +7,16 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 2; constexpr size_t no_insert_for_one_delete = 2;
// This test checks MultiIterator remove method ]. /**
// Each thread removes all duplicate data on random key. So removes are joint * This test checks MultiIterator remove method. Each thread removes all
// and scattered on same * duplicate data for a random key. So removes are joined and scattered on the
// key values. * same key values. Calls of remove method are interleaved with insert calls
// Calls of remove method are interleaved with insert calls which always * which always succeed.
// succeed. */
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
multimap_t skiplist; multimap_t skiplist;
@ -27,16 +28,21 @@ int main()
std::vector<long long> set(key_range, 0); std::vector<long long> set(key_range, 0);
long long sum = 0; long long sum = 0;
do { do
{
size_t num = rand(); size_t num = rand();
auto data = rand() % max_number; auto data = rand() % max_number;
if (rand_op()) { if (rand_op())
{
auto it = acc.find_multi(num); auto it = acc.find_multi(num);
if (it.has_value()) { if (it.has_value())
{
it++; it++;
while (it.has_value()) { while (it.has_value())
{
auto data_r = it->second; auto data_r = it->second;
if (it.remove()) { if (it.remove())
{
downcount--; downcount--;
set[num]--; set[num]--;
sum -= data_r; sum -= data_r;
@ -47,7 +53,9 @@ int main()
it++; it++;
} }
} }
} else { }
else
{
acc.insert(num, data); acc.insert(num, data);
downcount--; downcount--;
set[num]++; set[num]++;
@ -60,9 +68,11 @@ int main()
long set[key_range] = {0}; long set[key_range] = {0};
long long sums = 0; long long sums = 0;
for (auto &data : collect(futures)) { for (auto &data : collect(futures))
{
sums += data.second.first; sums += data.second.first;
for (int i = 0; i < key_range; i++) { for (int i = 0; i < key_range; i++)
{
set[i] += data.second.second[i]; set[i] += data.second.second[i];
} }
} }
@ -70,7 +80,8 @@ int main()
auto accessor = skiplist.access(); auto accessor = skiplist.access();
check_multi_iterator(accessor, key_range, set); check_multi_iterator(accessor, key_range, set);
for (auto &e : accessor) { for (auto &e : accessor)
{
set[e.first]--; set[e.first]--;
sums -= e.second; sums -= e.second;
} }

View File

@ -7,6 +7,8 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// TODO: document the test
// This test checks multimap. // This test checks multimap.
// Each thread removes random data. So removes are joint. // Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls which always // Calls of remove method are interleaved with insert calls which always
@ -14,6 +16,7 @@ constexpr size_t no_insert_for_one_delete = 1;
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
multimap_t skiplist; multimap_t skiplist;
std::atomic<long long> size(0); std::atomic<long long> size(0);
@ -26,17 +29,22 @@ int main()
std::vector<long long> set(key_range, 0); std::vector<long long> set(key_range, 0);
long long sum = 0; long long sum = 0;
do { do
{
size_t num = rand(); size_t num = rand();
auto data = num % max_number; auto data = num % max_number;
if (rand_op()) { if (rand_op())
if (acc.remove(num)) { {
if (acc.remove(num))
{
downcount--; downcount--;
set[num]--; set[num]--;
sum -= data; sum -= data;
size--; size--;
} }
} else { }
else
{
acc.insert(num, data); acc.insert(num, data);
downcount--; downcount--;
set[num]++; set[num]++;
@ -51,9 +59,11 @@ int main()
long set[key_range] = {0}; long set[key_range] = {0};
long long sums = 0; long long sums = 0;
long long size_calc = 0; long long size_calc = 0;
for (auto &data : collect(futures)) { for (auto &data : collect(futures))
{
sums += data.second.first; sums += data.second.first;
for (int i = 0; i < key_range; i++) { for (int i = 0; i < key_range; i++)
{
set[i] += data.second.second[i]; set[i] += data.second.second[i];
size_calc += data.second.second[i]; size_calc += data.second.second[i];
} }
@ -64,15 +74,18 @@ int main()
check_order<multimap_t>(accessor); check_order<multimap_t>(accessor);
auto bef_it = accessor.end(); auto bef_it = accessor.end();
for (int i = 0; i < key_range; i++) { for (int i = 0; i < key_range; i++)
{
auto it = accessor.find(i); auto it = accessor.find(i);
if (set[i] > 0) { if (set[i] > 0)
{
permanent_assert(it != accessor.end(), permanent_assert(it != accessor.end(),
"Multimap doesn't contain necessary element " "Multimap doesn't contain necessary element "
<< i); << i);
if (bef_it == accessor.end()) bef_it = accessor.find(i); if (bef_it == accessor.end()) bef_it = accessor.find(i);
for (int j = 0; j < set[i]; j++) { for (int j = 0; j < set[i]; j++)
{
permanent_assert( permanent_assert(
bef_it != accessor.end(), bef_it != accessor.end(),
"Previous iterator doesn't iterate through same " "Previous iterator doesn't iterate through same "
@ -89,7 +102,8 @@ int main()
bef_it++; bef_it++;
} }
for (int j = 0; j < set[i]; j++) { for (int j = 0; j < set[i]; j++)
{
permanent_assert(it != accessor.end(), permanent_assert(it != accessor.end(),
"Iterator doesn't iterate through same " "Iterator doesn't iterate through same "
"key entrys. Expected " "key entrys. Expected "
@ -110,7 +124,8 @@ int main()
} }
} }
for (auto &e : accessor) { for (auto &e : accessor)
{
set[e.first]--; set[e.first]--;
sums -= e.second; sums -= e.second;
} }

View File

@ -5,6 +5,8 @@ constexpr size_t key_range = 1e4;
constexpr size_t op_per_thread = 1e5; constexpr size_t op_per_thread = 1e5;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// TODO: document the test
// This test checks multiset. // This test checks multiset.
// Each thread removes random data. So removes are joint. // Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls which always // Calls of remove method are interleaved with insert calls which always
@ -12,6 +14,7 @@ constexpr size_t no_insert_for_one_delete = 1;
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
multiset_t skiplist; multiset_t skiplist;

View File

@ -6,6 +6,8 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 2; constexpr size_t no_insert_for_one_delete = 2;
// TODO: document the test
// This test checks remove method under pressure. // This test checks remove method under pressure.
// Threads will try to insert and remove keys aproximetly in the same order. // Threads will try to insert and remove keys aproximetly in the same order.
// This will force threads to compete intensly with each other. // This will force threads to compete intensly with each other.
@ -13,6 +15,7 @@ constexpr size_t no_insert_for_one_delete = 2;
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;

View File

@ -5,12 +5,15 @@ constexpr size_t key_range = 1e5;
constexpr size_t op_per_thread = 1e6; constexpr size_t op_per_thread = 1e6;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// TODO: document the test
// This test checks remove method under pressure. // This test checks remove method under pressure.
// Each thread removes it's own data. So removes are disjoint. // Each thread removes it's own data. So removes are disjoint.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;

View File

@ -7,6 +7,8 @@ constexpr size_t op_per_thread = 1e5;
constexpr size_t max_number = 10; constexpr size_t max_number = 10;
constexpr size_t no_insert_for_one_delete = 2; constexpr size_t no_insert_for_one_delete = 2;
// TODO: document the test
// This test checks remove method under pressure. // This test checks remove method under pressure.
// Each thread removes random data. So removes are joint. // Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
@ -24,17 +26,23 @@ int main()
long long sum = 0; long long sum = 0;
long long count = 0; long long count = 0;
do { do
{
auto num = rand(); auto num = rand();
auto data = num % max_number; auto data = num % max_number;
if (rand_op()) { if (rand_op())
if (acc.remove(num)) { {
if (acc.remove(num))
{
sum -= data; sum -= data;
downcount--; downcount--;
count--; count--;
} }
} else { }
if (acc.insert(num, data).second) { else
{
if (acc.insert(num, data).second)
{
sum += data; sum += data;
downcount--; downcount--;
count++; count++;
@ -48,12 +56,14 @@ int main()
auto accessor = skiplist.access(); auto accessor = skiplist.access();
long long sums = 0; long long sums = 0;
long long counters = 0; long long counters = 0;
for (auto &data : collect(futures)) { for (auto &data : collect(futures))
{
sums += data.second.first; sums += data.second.first;
counters += data.second.second; counters += data.second.second;
} }
for (auto &e : accessor) { for (auto &e : accessor)
{
sums -= e.second; sums -= e.second;
} }
permanent_assert(sums == 0, "Aproximetly Same values are present"); permanent_assert(sums == 0, "Aproximetly Same values are present");

View File

@ -5,12 +5,15 @@ constexpr size_t key_range = 1e4;
constexpr size_t op_per_thread = 1e5; constexpr size_t op_per_thread = 1e5;
constexpr size_t no_insert_for_one_delete = 2; constexpr size_t no_insert_for_one_delete = 2;
// TODO: document the test
// This test checks set. // This test checks set.
// Each thread removes random data. So removes are joint. // Each thread removes random data. So removes are joint.
// Calls of remove method are interleaved with insert calls. // Calls of remove method are interleaved with insert calls.
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
set_t skiplist; set_t skiplist;

View File

@ -8,6 +8,8 @@ constexpr size_t max_number = 10;
constexpr size_t no_find_per_change = 5; constexpr size_t no_find_per_change = 5;
constexpr size_t no_insert_for_one_delete = 1; constexpr size_t no_insert_for_one_delete = 1;
// TODO: document the test
// This test simulates behavior of transactions. // This test simulates behavior of transactions.
// Each thread makes a series of finds interleaved with method which change. // Each thread makes a series of finds interleaved with method which change.
// Exact ratio of finds per change and insert per delete can be regulated with // Exact ratio of finds per change and insert per delete can be regulated with
@ -15,6 +17,7 @@ constexpr size_t no_insert_for_one_delete = 1;
int main() int main()
{ {
init_log(); init_log();
memory_check(THREADS_NO, [] { memory_check(THREADS_NO, [] {
map_t skiplist; map_t skiplist;

View File

@ -1,11 +1,21 @@
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include "gtest/gtest.h"
#include "logging/default.cpp" #include "logging/default.cpp"
#include "utils/timer/timer.hpp" #include "utils/timer/timer.hpp"
#include "utils/assert.hpp"
using namespace std::chrono_literals; using namespace std::chrono_literals;
/**
* Creates a test timer which will log timeout message at the timeout event.
*
* @param counter how many time units the timer has to wait
*
* @return shared pointer to a timer
*/
Timer::sptr create_test_timer(int64_t counter) Timer::sptr create_test_timer(int64_t counter)
{ {
return std::make_shared<Timer>( return std::make_shared<Timer>(
@ -13,16 +23,38 @@ Timer::sptr create_test_timer(int64_t counter)
); );
} }
int main(void) TEST(TimerSchedulerTest, TimerSchedulerExecution)
{ {
// initialize the timer
TimerScheduler<TimerSet, std::chrono::seconds> timer_scheduler; TimerScheduler<TimerSet, std::chrono::seconds> timer_scheduler;
// run the timer
timer_scheduler.run(); timer_scheduler.run();
// add a couple of test timers
for (int64_t i = 1; i <= 3; ++i) { for (int64_t i = 1; i <= 3; ++i) {
timer_scheduler.add(create_test_timer(i)); timer_scheduler.add(create_test_timer(i));
} }
// wait for that timers
std::this_thread::sleep_for(4s); std::this_thread::sleep_for(4s);
ASSERT_EQ(timer_scheduler.size(), 0);
// add another test timer
timer_scheduler.add(create_test_timer(1)); timer_scheduler.add(create_test_timer(1));
// wait for another timer
std::this_thread::sleep_for(2s); std::this_thread::sleep_for(2s);
// the test is done
timer_scheduler.stop(); timer_scheduler.stop();
return 0;
ASSERT_EQ(timer_scheduler.size(), 0);
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} }

View File

@ -44,6 +44,7 @@ foreach(test_cpp ${test_type_cpps})
target_link_libraries(${target_name} dl) target_link_libraries(${target_name} dl)
# register test # register test
add_test(${target_name} ${exec_name}) add_test(${target_name} ${exec_name}
--gtest_output=xml:${CMAKE_BINARY_DIR}/test_results/${target_name}.xml)
endforeach() endforeach()

View File

@ -1,22 +1,17 @@
#define CATCH_CONFIG_MAIN #include "gtest/gtest.h"
#include "catch.hpp"
#include <functional>
#include "data_structures/bloom/bloom_filter.hpp"
#include "utils/command_line/arguments.hpp" #include "utils/command_line/arguments.hpp"
#include "utils/hashing/fnv64.hpp" #include "utils/hashing/fnv64.hpp"
#include "data_structures/bloom/bloom_filter.hpp"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wwritable-strings"
using StringHashFunction = std::function<uint64_t(const std::string &)>; using StringHashFunction = std::function<uint64_t(const std::string &)>;
TEST_CASE("BloomFilter Test") TEST(BloomFilterTest, InsertContains)
{ {
StringHashFunction hash1 = fnv64<std::string>; StringHashFunction hash1 = fnv64<std::string>;
StringHashFunction hash2 = fnv1a64<std::string>; StringHashFunction hash2 = fnv1a64<std::string>;
auto c = [](auto x) -> int { return x % 4; };
std::vector<StringHashFunction> funcs = {hash1, hash2}; std::vector<StringHashFunction> funcs = {hash1, hash2};
BloomFilter<std::string, 64> bloom(funcs); BloomFilter<std::string, 64> bloom(funcs);
@ -24,19 +19,21 @@ TEST_CASE("BloomFilter Test")
std::string test = "test"; std::string test = "test";
std::string kifla = "kifla"; std::string kifla = "kifla";
std::cout << hash1(test) << std::endl; bool contains_test = bloom.contains(test);
std::cout << hash2(test) << std::endl; ASSERT_EQ(contains_test, false);
std::cout << hash1(kifla) << std::endl;
std::cout << hash2(kifla) << std::endl;
std::cout << bloom.contains(test) << std::endl;
bloom.insert(test); bloom.insert(test);
std::cout << bloom.contains(test) << std::endl; contains_test = bloom.contains(test);
ASSERT_EQ(contains_test, true);
std::cout << bloom.contains(kifla) << std::endl; bool contains_kifla = bloom.contains(kifla);
ASSERT_EQ(contains_kifla, false);
bloom.insert(kifla); bloom.insert(kifla);
std::cout << bloom.contains(kifla) << std::endl; contains_kifla = bloom.contains(kifla);
ASSERT_EQ(contains_kifla, true);
} }
#pragma clang diagnostic pop int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -5,15 +5,16 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "gtest/gtest.h"
#include "communication/bolt/v1/transport/chunked_decoder.hpp" #include "communication/bolt/v1/transport/chunked_decoder.hpp"
using byte = unsigned char; using byte = unsigned char;
void print_hex(byte x) { printf("%02X ", static_cast<byte>(x)); } void print_hex(byte x) { printf("%02X ", static_cast<byte>(x)); }
class DummyStream struct DummyStream
{ {
public:
void write(const byte *values, size_t n) void write(const byte *values, size_t n)
{ {
data.insert(data.end(), values, values + n); data.insert(data.end(), values, values + n);
@ -35,25 +36,33 @@ static constexpr size_t N = std::extent<decltype(chunks)>::value;
std::string decoded = "A quick brown fox jumps over a lazy dog"; std::string decoded = "A quick brown fox jumps over a lazy dog";
int main(void) TEST(ChunkedDecoderTest, WriteString)
{ {
// DummyStream stream; DummyStream stream;
// Decoder decoder(stream); Decoder decoder(stream);
// for(size_t i = 0; i < N; ++i) for(size_t i = 0; i < N; ++i)
// { {
// auto& chunk = chunks[i]; auto & chunk = chunks[i];
// auto finished = decoder.decode(chunk.data(), chunk.size()); logging::info("Chunk size: {}", chunk.size());
// // break early if finished const byte* start = chunk.data();
// if(finished) auto finished = decoder.decode(start, chunk.size());
// break;
// }
// assert(decoded.size() == stream.data.size()); // break early if finished
if(finished)
break;
}
// for(size_t i = 0; i < decoded.size(); ++i) // check validity
// assert(decoded[i] == stream.data[i]); ASSERT_EQ(decoded.size(), stream.data.size());
for(size_t i = 0; i < decoded.size(); ++i)
return 0; ASSERT_EQ(decoded[i], stream.data[i]);
} }
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -3,6 +3,8 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include "gtest/gtest.h"
#include "communication/bolt/v1/transport/chunked_encoder.hpp" #include "communication/bolt/v1/transport/chunked_encoder.hpp"
#include "logging/default.hpp" #include "logging/default.hpp"
#include "logging/streams/stdout.hpp" #include "logging/streams/stdout.hpp"
@ -54,61 +56,68 @@ void write_ff(Encoder &encoder, size_t n)
void check_ff(DummyStream &stream, size_t n) void check_ff(DummyStream &stream, size_t n)
{ {
for (size_t i = 0; i < n; ++i) for (size_t i = 0; i < n; ++i)
assert(stream.pop() == byte('\xFF')); ASSERT_EQ(stream.pop(), byte('\xFF'));
(void)stream; (void)stream;
} }
int main(void) using encoder_t = bolt::ChunkedEncoder<DummyStream>;
TEST(ChunkedEncoderTest, Encode)
{ {
// TODO: write new test DummyStream stream;
encoder_t encoder(stream);
size_t chunk_size = encoder_t::chunk_size;
// logging::init_async(); write_ff(encoder, 10);
// logging::log->pipe(std::make_unique<Stdout>()); write_ff(encoder, 10);
// DummyStream stream; encoder.write_chunk();
// bolt::ChunkedEncoder<DummyStream> encoder(stream);
// write_ff(encoder, 10); write_ff(encoder, 10);
// write_ff(encoder, 10); write_ff(encoder, 10);
// encoder.flush(); encoder.write_chunk();
// write_ff(encoder, 10); // this should be two chunks, one of size 65533 and the other of size 1467
// write_ff(encoder, 10); write_ff(encoder, 67000);
// encoder.flush(); encoder.write_chunk();
// // this should be two chunks, one of size 65533 and the other of size 1467 for (int i = 0; i < 10000; ++i)
// write_ff(encoder, 67000); write_ff(encoder, 1500);
// encoder.flush(); encoder.write_chunk();
// for (int i = 0; i < 10000; ++i) ASSERT_EQ(stream.pop_size(), 20);
// write_ff(encoder, 1500); check_ff(stream, 20);
// encoder.flush(); ASSERT_EQ(stream.pop_size(), 0);
// assert(stream.pop_size() == 20); ASSERT_EQ(stream.pop_size(), 20);
// check_ff(stream, 20); check_ff(stream, 20);
// assert(stream.pop_size() == 0); ASSERT_EQ(stream.pop_size(), 0);
// assert(stream.pop_size() == 20); ASSERT_EQ(stream.pop_size(), chunk_size);
// check_ff(stream, 20); check_ff(stream, chunk_size);
// assert(stream.pop_size() == 0); ASSERT_EQ(stream.pop_size(), 0);
// assert(stream.pop_size() == encoder.chunk_size); ASSERT_EQ(stream.pop_size(), 1467);
// check_ff(stream, encoder.chunk_size); check_ff(stream, 1467);
// assert(stream.pop_size() == 1467); ASSERT_EQ(stream.pop_size(), 0);
// check_ff(stream, 1467);
// assert(stream.pop_size() == 0);
// size_t k = 10000 * 1500; size_t k = 10000 * 1500;
// while (k > 0) { while (k > 0) {
// auto size = k > encoder.chunk_size ? encoder.chunk_size : k; auto size = k > chunk_size ? chunk_size : k;
// assert(stream.pop_size() == size); ASSERT_EQ(stream.pop_size(), size);
// check_ff(stream, size); check_ff(stream, size);
ASSERT_EQ(stream.pop_size(), 0);
// k -= size; k -= size;
// } }
ASSERT_EQ(stream.pop_size(), 0);
// assert(stream.pop_size() == 0); }
return 0; int main(int argc, char **argv)
{
logging::init_sync();
logging::log->pipe(std::make_unique<Stdout>());
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
} }