From 4d6c315c1e943642bd639c6647e4d76baa418aee Mon Sep 17 00:00:00 2001 From: Marko Budiselic <mbudiselicbuda@gmail.com> Date: Sun, 18 Dec 2016 19:21:29 +0100 Subject: [PATCH 1/2] Block Allocator Test - initial implementation Summary: Block Allocator Test - initial implementation Test Plan: ctest -R memgraph_unit_block_allocator Reviewers: sale Subscribers: sale, buda Differential Revision: https://memgraph.phacility.com/D20 --- include/utils/auto_scope.hpp | 7 ++ include/utils/memory/block_allocator.hpp | 39 ++++++--- tests/unit/CMakeLists.txt | 2 + tests/unit/basic_bloom_filter.cpp | 47 +++++----- tests/unit/block_allocator.cpp | 24 +++++ tests/unit/parameter_index.cpp | 5 +- tests/unit/program_argument.cpp | 106 ++++++++++++----------- 7 files changed, 142 insertions(+), 88 deletions(-) create mode 100644 tests/unit/block_allocator.cpp diff --git a/include/utils/auto_scope.hpp b/include/utils/auto_scope.hpp index 10de5751f..119078a91 100644 --- a/include/utils/auto_scope.hpp +++ b/include/utils/auto_scope.hpp @@ -55,3 +55,10 @@ private: TOKEN_PASTE(auto_, counter)(TOKEN_PASTE(auto_func_, counter)); #define Auto(Destructor) Auto_INTERNAL(Destructor, __COUNTER__) + +// -- example: +// Auto(f()); +// -- is expended to: +// auto auto_func_1 = [&]() { f(); }; +// OnScopeExit<decltype(auto_func_1)> auto_1(auto_func_1); +// -- f() is called at the end of a scope diff --git a/include/utils/memory/block_allocator.hpp b/include/utils/memory/block_allocator.hpp index f0c0e6475..f7eb3791f 100644 --- a/include/utils/memory/block_allocator.hpp +++ b/include/utils/memory/block_allocator.hpp @@ -5,6 +5,9 @@ #include "utils/auto_scope.hpp" +/* @brief Allocates blocks of block_size and stores + * the pointers on allocated blocks inside a vector. + */ template <size_t block_size> class BlockAllocator { @@ -23,29 +26,45 @@ public: BlockAllocator(size_t capacity = 0) { for (size_t i = 0; i < capacity; ++i) - blocks.emplace_back(); + unused_.emplace_back(); } ~BlockAllocator() { - for (auto b : blocks) { - free(b.data); - } - blocks.clear(); + for (auto block : unused_) + free(block.data); + unused_.clear(); + for (auto block : release_) + free(block.data); + release_.clear(); + } + + size_t unused_size() const + { + return unused_.size(); + } + + size_t release_size() const + { + return release_.size(); } // Returns nullptr on no memory. void *acquire() { - if (blocks.size() == 0) blocks.emplace_back(); + if (unused_.size() == 0) unused_.emplace_back(); - auto ptr = blocks.back().data; - Auto(blocks.pop_back()); + auto ptr = unused_.back().data; + Auto(unused_.pop_back()); return ptr; } - void release(void *ptr) { blocks.emplace_back(ptr); } + void release(void *ptr) { release_.emplace_back(ptr); } private: - std::vector<Block> blocks; + // TODO: try implement with just one vector + // but consecutive acquire release calls should work + // TODO: measure first! + std::vector<Block> unused_; + std::vector<Block> release_; }; diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index df6ecb100..85b360288 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -26,6 +26,8 @@ foreach(test_cpp ${test_type_cpps}) set_target_properties(${target_name} PROPERTIES OUTPUT_NAME ${exec_name}) # link libraries + # gtest + target_link_libraries(${target_name} gtest gtest_main) # filesystem target_link_libraries(${target_name} stdc++fs) # threads (cross-platform) diff --git a/tests/unit/basic_bloom_filter.cpp b/tests/unit/basic_bloom_filter.cpp index ac4df7fc2..15a41294c 100644 --- a/tests/unit/basic_bloom_filter.cpp +++ b/tests/unit/basic_bloom_filter.cpp @@ -9,37 +9,34 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wwritable-strings" -using StringHashFunction = std::function<uint64_t(const std::string&)>; - -TEST_CASE("BloomFilter Test") { - StringHashFunction hash1 = fnv64<std::string>; - StringHashFunction hash2 = fnv1a64<std::string>; +using StringHashFunction = std::function<uint64_t(const std::string &)>; - auto c = [](auto x) -> int { - return x % 4; - } ; - std::vector<StringHashFunction> funcs = { - hash1, hash2 - }; +TEST_CASE("BloomFilter Test") +{ + StringHashFunction hash1 = fnv64<std::string>; + StringHashFunction hash2 = fnv1a64<std::string>; - BloomFilter<std::string, 64> bloom(funcs); + auto c = [](auto x) -> int { return x % 4; }; + std::vector<StringHashFunction> funcs = {hash1, hash2}; - std::string test = "test"; - std::string kifla = "kifla"; + BloomFilter<std::string, 64> bloom(funcs); - std::cout << hash1(test) << std::endl; - std::cout << hash2(test) << std::endl; - - std::cout << hash1(kifla) << std::endl; - std::cout << hash2(kifla) << std::endl; + std::string test = "test"; + std::string kifla = "kifla"; - std::cout << bloom.contains(test) << std::endl; - bloom.insert(test); - std::cout << bloom.contains(test) << std::endl; + std::cout << hash1(test) << std::endl; + std::cout << hash2(test) << std::endl; - std::cout << bloom.contains(kifla) << std::endl; - bloom.insert(kifla); - std::cout << bloom.contains(kifla) << std::endl; + std::cout << hash1(kifla) << std::endl; + std::cout << hash2(kifla) << std::endl; + + std::cout << bloom.contains(test) << std::endl; + bloom.insert(test); + std::cout << bloom.contains(test) << std::endl; + + std::cout << bloom.contains(kifla) << std::endl; + bloom.insert(kifla); + std::cout << bloom.contains(kifla) << std::endl; } #pragma clang diagnostic pop diff --git a/tests/unit/block_allocator.cpp b/tests/unit/block_allocator.cpp new file mode 100644 index 000000000..35bf9cfdc --- /dev/null +++ b/tests/unit/block_allocator.cpp @@ -0,0 +1,24 @@ +#include "gtest/gtest.h" + +#include "utils/memory/block_allocator.hpp" + +TEST(BlockAllocatorTest, UnusedVsReleaseSize) +{ + BlockAllocator<64> block_allocator(10); + void *block = block_allocator.acquire(); + block_allocator.release(block); + EXPECT_EQ(block_allocator.unused_size(), 9); + EXPECT_EQ(block_allocator.release_size(), 1); +} + +TEST(BlockAllocatorTest, CountMallocAndFreeCalls) +{ + // TODO: implementation + EXPECT_EQ(true, true); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit/parameter_index.cpp b/tests/unit/parameter_index.cpp index 542591dd6..b2d137c79 100644 --- a/tests/unit/parameter_index.cpp +++ b/tests/unit/parameter_index.cpp @@ -8,12 +8,13 @@ using ParameterIndexKey::Type::Projection; auto main() -> int { - std::map<ParameterIndexKey, uint64_t> parameter_index; + std::map<ParameterIndexKey, uint64_t> parameter_index; parameter_index[ParameterIndexKey(InternalId, "n1")] = 0; parameter_index[ParameterIndexKey(InternalId, "n2")] = 1; - permanent_assert(parameter_index.size() == 2, "Parameter index size should be 2"); + permanent_assert(parameter_index.size() == 2, + "Parameter index size should be 2"); return 0; } diff --git a/tests/unit/program_argument.cpp b/tests/unit/program_argument.cpp index a12ae190f..c5c54996e 100644 --- a/tests/unit/program_argument.cpp +++ b/tests/unit/program_argument.cpp @@ -6,80 +6,84 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wwritable-strings" -TEST_CASE("ProgramArgument FlagOnly Test") { - CLEAR_ARGS(); +TEST_CASE("ProgramArgument FlagOnly Test") +{ + CLEAR_ARGS(); - int argc = 2; - char* argv[] = {"ProgramArgument FlagOnly Test", "-test"}; + int argc = 2; + char *argv[] = {"ProgramArgument FlagOnly Test", "-test"}; - REGISTER_ARGS(argc, argv); - REGISTER_REQUIRED_ARGS({"-test"}); + REGISTER_ARGS(argc, argv); + REGISTER_REQUIRED_ARGS({"-test"}); - REQUIRE(CONTAINS_FLAG("-test") == true); + REQUIRE(CONTAINS_FLAG("-test") == true); } -TEST_CASE("ProgramArgument Single Entry Test") { - CLEAR_ARGS(); +TEST_CASE("ProgramArgument Single Entry Test") +{ + CLEAR_ARGS(); - int argc = 3; - char* argv[] = {"ProgramArgument Single Entry Test", "-bananas", "99"}; + int argc = 3; + char *argv[] = {"ProgramArgument Single Entry Test", "-bananas", "99"}; - REGISTER_REQUIRED_ARGS({"-bananas"}); - REGISTER_ARGS(argc, argv); + REGISTER_REQUIRED_ARGS({"-bananas"}); + REGISTER_ARGS(argc, argv); - REQUIRE(GET_ARG("-bananas", "100").get_int() == 99); + REQUIRE(GET_ARG("-bananas", "100").get_int() == 99); } -TEST_CASE("ProgramArgument Multiple Entries Test") { - CLEAR_ARGS(); +TEST_CASE("ProgramArgument Multiple Entries Test") +{ + CLEAR_ARGS(); - int argc = 4; - char* argv[] = {"ProgramArgument Multiple Entries Test", "-files", - "first_file.txt", "second_file.txt"}; + int argc = 4; + char *argv[] = {"ProgramArgument Multiple Entries Test", "-files", + "first_file.txt", "second_file.txt"}; - REGISTER_ARGS(argc, argv); + REGISTER_ARGS(argc, argv); - auto files = GET_ARGS("-files", {}); + auto files = GET_ARGS("-files", {}); - REQUIRE(files[0].get_string() == "first_file.txt"); + REQUIRE(files[0].get_string() == "first_file.txt"); } -TEST_CASE("ProgramArgument Combination Test") { - CLEAR_ARGS(); +TEST_CASE("ProgramArgument Combination Test") +{ + CLEAR_ARGS(); - int argc = 14; - char* argv[] = {"ProgramArgument Combination Test", - "-run_tests", - "-tests", - "Test1", - "Test2", - "Test3", - "-run_times", - "10", - "-export", - "test1.txt", - "test2.txt", - "test3.txt", - "-import", - "data.txt"}; + int argc = 14; + char *argv[] = {"ProgramArgument Combination Test", + "-run_tests", + "-tests", + "Test1", + "Test2", + "Test3", + "-run_times", + "10", + "-export", + "test1.txt", + "test2.txt", + "test3.txt", + "-import", + "data.txt"}; - REGISTER_ARGS(argc, argv); + REGISTER_ARGS(argc, argv); - REQUIRE(CONTAINS_FLAG("-run_tests") == true); + REQUIRE(CONTAINS_FLAG("-run_tests") == true); - auto tests = GET_ARGS("-tests", {}); - REQUIRE(tests[0].get_string() == "Test1"); - REQUIRE(tests[1].get_string() == "Test2"); - REQUIRE(tests[2].get_string() == "Test3"); + auto tests = GET_ARGS("-tests", {}); + REQUIRE(tests[0].get_string() == "Test1"); + REQUIRE(tests[1].get_string() == "Test2"); + REQUIRE(tests[2].get_string() == "Test3"); - REQUIRE(GET_ARG("-run_times", "0").get_int() == 10); + REQUIRE(GET_ARG("-run_times", "0").get_int() == 10); - auto exports = GET_ARGS("-export", {}); - REQUIRE(exports[0].get_string() == "test1.txt"); - REQUIRE(exports[1].get_string() == "test2.txt"); - REQUIRE(exports[2].get_string() == "test3.txt"); + auto exports = GET_ARGS("-export", {}); + REQUIRE(exports[0].get_string() == "test1.txt"); + REQUIRE(exports[1].get_string() == "test2.txt"); + REQUIRE(exports[2].get_string() == "test3.txt"); - REQUIRE(GET_ARG("-import", "test.txt").get_string() == "data.txt"); + REQUIRE(GET_ARG("-import", "test.txt").get_string() == "data.txt"); } #pragma clang diagnostic pop From dc3433aa8ad283df577fbabe69f736aa6678fce3 Mon Sep 17 00:00:00 2001 From: Marko Budiselic <mbudiselicbuda@gmail.com> Date: Sun, 18 Dec 2016 20:26:08 +0100 Subject: [PATCH 2/2] Stack Allocator Unit Test Summary: Stack Allocator Unit Test Test Plan: manual (unit tests are not passing because malloc and free counters have to be added) Reviewers: sale Subscribers: sale, buda Differential Revision: https://memgraph.phacility.com/D21 --- include/utils/memory/stack_allocator.hpp | 1 + tests/unit/block_allocator.cpp | 2 +- tests/unit/stack_allocator.cpp | 34 ++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tests/unit/stack_allocator.cpp diff --git a/include/utils/memory/stack_allocator.hpp b/include/utils/memory/stack_allocator.hpp index 287bdad6a..15623e49d 100644 --- a/include/utils/memory/stack_allocator.hpp +++ b/include/utils/memory/stack_allocator.hpp @@ -3,6 +3,7 @@ #include <cmath> #include "utils/exceptions/out_of_memory.hpp" +#include "utils/likely.hpp" #include "utils/memory/block_allocator.hpp" // http://en.cppreference.com/w/cpp/language/new diff --git a/tests/unit/block_allocator.cpp b/tests/unit/block_allocator.cpp index 35bf9cfdc..e2de1e405 100644 --- a/tests/unit/block_allocator.cpp +++ b/tests/unit/block_allocator.cpp @@ -14,7 +14,7 @@ TEST(BlockAllocatorTest, UnusedVsReleaseSize) TEST(BlockAllocatorTest, CountMallocAndFreeCalls) { // TODO: implementation - EXPECT_EQ(true, true); + EXPECT_EQ(true, false); } int main(int argc, char **argv) diff --git a/tests/unit/stack_allocator.cpp b/tests/unit/stack_allocator.cpp new file mode 100644 index 000000000..006ffbe36 --- /dev/null +++ b/tests/unit/stack_allocator.cpp @@ -0,0 +1,34 @@ +#include "gtest/gtest.h" + +#include "utils/memory/stack_allocator.hpp" + +struct Object +{ + int a; + int b; + + Object(int a, int b) : a(a), b(b) {} +}; + +TEST(StackAllocatorTest, AllocationAndObjectValidity) +{ + StackAllocator allocator; + for (int i = 0; i < 64 * 1024; ++i) + { + auto object = allocator.make<Object>(1, 2); + ASSERT_EQ(object->a, 1); + ASSERT_EQ(object->b, 2); + } +} + +TEST(StackAllocatorTest, CountMallocAndFreeCalls) +{ + // TODO: implementation + EXPECT_EQ(true, false); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}