diff --git a/include/utils/random/generator.h b/include/utils/random/generator.h new file mode 100644 index 000000000..bf110a99a --- /dev/null +++ b/include/utils/random/generator.h @@ -0,0 +1,75 @@ +#include +#include + +// namespace ::utils +namespace utils { + +// namespace utils::random +namespace random { + +template +class RandomGenerator { + private: + std::random_device device_; + + protected: + Generator gen_; + Distribution dist_; + + public: + RandomGenerator(Distribution dist) : gen_(device_()), dist_(dist) {} +}; + +class StringGenerator + : public RandomGenerator, + std::default_random_engine> { + private: + int size_; + + public: + StringGenerator(int size) + : RandomGenerator(std::uniform_int_distribution(32, 126)), + size_(size) {} + + std::string next(int size) { + std::string random_string; + random_string.reserve(size); + + for (int i = 0; i < size; i++) random_string += (dist_(gen_) + '\0'); + + return random_string; + } + + std::string next() { return next(size_); } +}; + +template +class NumberGenerator : public RandomGenerator { + public: + NumberGenerator(DistributionRangeType start, DistributionRangeType end) + : RandomGenerator(Distribution(start, end)) {} + + auto next() { return this->dist_(this->gen_); } +}; + +template +class PairGenerator { + private: + FirstGenerator *first_; + SecondGenerator *second_; + + public: + PairGenerator(FirstGenerator *first, SecondGenerator *second) + : first_(first), second_(second) {} + auto next() { return std::make_pair(first_->next(), second_->next()); } +}; + +template +auto generate_vector(RandomGenerator &gen, int size) { + std::vector elements(size); + for (int i = 0; i < size; i++) elements[i] = gen.next(); + return elements; +} + +}; // namespace utils::random +}; // namespace ::utils diff --git a/include/utils/time/timer.hpp b/include/utils/time/timer.hpp index e8332c5b3..e989ba600 100644 --- a/include/utils/time/timer.hpp +++ b/include/utils/time/timer.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/tests/benchmark/CMakeLists.txt b/tests/benchmark/CMakeLists.txt index ef94ffd2c..a30271887 100644 --- a/tests/benchmark/CMakeLists.txt +++ b/tests/benchmark/CMakeLists.txt @@ -12,6 +12,10 @@ foreach(ONE_BENCH_CPP ${ALL_BENCH_CPP}) add_executable(${TARGET_NAME} ${ONE_BENCH_CPP}) set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${ONE_BENCH_EXEC}) target_link_libraries(${TARGET_NAME} benchmark ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(${TARGET_NAME} memgraph) + target_link_libraries(${TARGET_NAME} ${fmt_static_lib}) + target_link_libraries(${TARGET_NAME} Threads::Threads) + target_link_libraries(${TARGET_NAME} ${yaml_static_lib}) add_test(${TARGET_NAME} ${ONE_BENCH_EXEC}) endforeach() diff --git a/tests/benchmark/data_structures/concurrent/concurrent_map.cpp b/tests/benchmark/data_structures/concurrent/concurrent_map.cpp new file mode 100644 index 000000000..6b4da1c3f --- /dev/null +++ b/tests/benchmark/data_structures/concurrent/concurrent_map.cpp @@ -0,0 +1,221 @@ +#include +#include + +#include "data_structures/concurrent/concurrent_map.hpp" +#include "logging/default.hpp" +#include "logging/streams/stdout.hpp" +#include "utils/random/generator.h" + +#include "benchmark/benchmark_api.h" + +/* + ConcurrentMap Benchmark Test: + - tests time of Insertion, Contain and Delete operations + + - benchmarking time per operation + + - test run ConcurrentMap with the following keys and values: + - + - + - + - + + - tests run single and multi threaded in range (1, Max_Threads_Per_Cpu) + + TODO(sale) implements configurable command line arguments on start +*/ + +using utils::random::NumberGenerator; +using utils::random::PairGenerator; +using utils::random::StringGenerator; + +using IntegerGenerator = NumberGenerator, + std::default_random_engine, int>; + +template +static void InsertValue(benchmark::State& state, ConcurrentMap* map, + const std::vector>& elements) { + while (state.KeepRunning()) { + auto accessor = map->access(); + for (int start = 0; start < state.range(0); start++) { + accessor.insert(elements[start].first, elements[start].second); + } + } + state.SetComplexityN(state.range(0)); +} + +template +static void DeleteValue(benchmark::State& state, ConcurrentMap* map, + const std::vector> elements) { + while (state.KeepRunning()) { + auto accessor = map->access(); + for (int start = 0; start < state.range(0); start++) { + accessor.remove(elements[start].first); + } + } + state.SetComplexityN(state.range(0)); +} + +template +static void ContainsValue(benchmark::State& state, ConcurrentMap* map, + const std::vector> elements) { + while (state.KeepRunning()) { + auto accessor = map->access(); + for (int start = 0; start < state.range(0); start++) { + accessor.contains(elements[start].first); + } + } + state.SetComplexityN(state.range(0)); +} + +auto BM_InsertValue = [](benchmark::State& state, auto* map, auto& elements) { + InsertValue(state, map, elements); +}; + +auto BM_DeleteValue = [](benchmark::State& state, auto* map, auto elements) { + DeleteValue(state, map, elements); +}; + +auto BM_ContainsValue = [](benchmark::State& state, auto* map, auto elements) { + ContainsValue(state, map, elements); +}; + +int main(int argc, char** argv) { + int MAX_ELEMENTS = 1 << 14; + int MULTIPLIER = 2; + int MAX_THREADS = (int)std::thread::hardware_concurrency(); + + logging::init_async(); + logging::log->pipe(std::make_unique()); + + StringGenerator sg(128); + IntegerGenerator ig(0, 1000000); + + /* + Creates RandomGenerators, ConcurentMaps and Random Element Vectors for the + following use cases: + + Map elements contain keys and value for: + , + + + + */ + + PairGenerator piig(&ig, &ig); + PairGenerator pssg(&sg, &sg); + PairGenerator psig(&sg, &ig); + PairGenerator pisg(&ig, &sg); + + ConcurrentMap ii_map; + ConcurrentMap is_map; + ConcurrentMap si_map; + ConcurrentMap ss_map; + + auto ii_elems = utils::random::generate_vector(piig, MAX_ELEMENTS); + auto is_elems = utils::random::generate_vector(pisg, MAX_ELEMENTS); + auto si_elems = utils::random::generate_vector(psig, MAX_ELEMENTS); + auto ss_elems = utils::random::generate_vector(pssg, MAX_ELEMENTS); + + /* insertion Tests */ + + for (int t = 1; t <= MAX_THREADS; t *= 2) { + benchmark::RegisterBenchmark("InsertValue[Int, Int]", BM_InsertValue, + &ii_map, ii_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("InsertValue[Int, String] (size:128 chars)", + BM_InsertValue, &is_map, is_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("InsertValue[String, Int] (size:128 chars)", + BM_InsertValue, &si_map, si_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("InsertValue[String, String] (size:128 chars)", + BM_InsertValue, &ss_map, ss_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + } + + // Contains Benchmark Tests + + for (int t = 1; t <= MAX_THREADS; t *= 2) { + benchmark::RegisterBenchmark("ContainsValue[Int, Int]", BM_ContainsValue, + &ii_map, ii_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("ContainsValue[Int, String] (size:128 chars)", + BM_ContainsValue, &is_map, is_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("ContainsValue[String, Int] (size:128 chars)", + BM_ContainsValue, &si_map, si_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark( + "ContainsValue[String, String] (size:128 chars)", BM_ContainsValue, + &ss_map, ss_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + } + + // Deletion Banchamark Tests + + for (int t = 1; t <= MAX_THREADS; t *= 2) { + benchmark::RegisterBenchmark("DeleteValue[Int, Int]", BM_DeleteValue, + &ii_map, ii_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("DeleteValue[Int, String] (size:128 chars)", + BM_DeleteValue, &is_map, is_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("DeleteValue[String, Int] (size:128 chars)", + BM_DeleteValue, &si_map, si_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + + benchmark::RegisterBenchmark("DeleteValue[String, String] (size:128 chars)", + BM_DeleteValue, &ss_map, ss_elems) + ->RangeMultiplier(MULTIPLIER) + ->Range(1, MAX_ELEMENTS) + ->Complexity(benchmark::oN) + ->Threads(t); + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + + return 0; +} diff --git a/tests/benchmark/query/strip/stripper.cpp b/tests/benchmark/query/strip/stripper.cpp new file mode 100644 index 000000000..9a9caffb9 --- /dev/null +++ b/tests/benchmark/query/strip/stripper.cpp @@ -0,0 +1,44 @@ +#include "logging/default.hpp" +#include "logging/streams/stdout.hpp" +#include "utils/time/timer.hpp" +#include "query/preprocesor.hpp" + +#include "benchmark/benchmark_api.h" +#include "yaml-cpp/yaml.h" + +auto BM_Strip = [](benchmark::State& state, auto& function, std::string query) { + while (state.KeepRunning()) { + for (int start = 0; start < state.range(0); start++) { + function(query); + } + } + state.SetComplexityN(state.range(0)); +}; + +int main(int argc, char** argv) { + logging::init_async(); + logging::log->pipe(std::make_unique()); + + YAML::Node dataset = YAML::LoadFile( + "../../tests/data/cypher_queries/stripper/query_dict.yaml"); + + QueryPreprocessor processor; + using std::placeholders::_1; + std::function preprocess = + std::bind(&QueryPreprocessor::preprocess, &processor, _1); + + auto tests = dataset["benchmark_queries"].as>(); + for (auto& test : tests) { + auto* benchmark = + benchmark::RegisterBenchmark(test.c_str(), BM_Strip, preprocess, test) + ->RangeMultiplier(2) + ->Range(1, 8 << 10) + ->Complexity(benchmark::oN); + ; + } + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + + return 0; +} diff --git a/tests/data/cypher_queries/stripper/query_dict.yaml b/tests/data/cypher_queries/stripper/query_dict.yaml new file mode 100644 index 000000000..549733ce4 --- /dev/null +++ b/tests/data/cypher_queries/stripper/query_dict.yaml @@ -0,0 +1,42 @@ +benchmark_queries: + - "MATCH (a) RETURN size(collect(a))" + + - "CREATE (a:L), (b1), (b2) CREATE (a)-[:A]->(b1), (a)-[:A]->(b2)" + + - "MATCH (a:L)-[rel]->(b) RETURN a, count(*)" + + - "CREATE ({division: 'Sweden'})" + + - "MATCH (n) RETURN n.division, count(*) ORDER BY count(*) DESC, n.division ASC" + + - "UNWIND ['a', 'b', 'B', null, 'abc', 'abc1'] AS i RETURN max(i)" + + - "CREATE ({created: true})" + + - "MATCH (a)-[r]-(b) DELETE r, a, b RETURN count(*) AS c" + + - "MATCH (u:User) WITH {key: u} AS nodes DELETE nodes.key" + + - "CREATE ()-[:T {id: 42, alive: true, name: kifla, height=4.2}]->()" + + - "MATCH p = ()-[r:T]-() WHERE r.id = 42 DELETE r" + + - "UNWIND range(0, 1000) AS i CREATE (:A {id: i}) MERGE (:B {id: i % 10})" + + - "MATCH (n) WHERE NOT(n.name = 'apa' AND false) RETURN n" + + - "CREATE ()-[:REL {property1: 12, property2: 24}]->()" + + - "MATCH (n:A) WHERE n.name = 'Andres' SET n.name = 'Michael' RETURN n" + + - "MATCH (n:A) SET (n).name = 'memgraph' RETURN n" + + - "CREATE (a {foo: [1, 2, 3]}) SET a.foo = a.foo + [4, 5] RETURN a.foo" + + - "MATCH (n:X {foo: 'A'}) SET n = {foo: 'B', baz: 'C'} RETURN n" + + - "MATCH (n:X {foo: 'A'}) SET n += {foo: null} RETURN n" + + - "MATCH (n) WITH n LIMIT toInteger(ceil(1.7)) RETURN count(*) AS count" + + - "MATCH (a:A), (b:B) MERGE (a)-[r:TYPE]->(b) ON CREATE SET r.name = 'Lola' RETURN count(r)"