diff --git a/benchmark/allocator b/benchmark/allocator new file mode 100755 index 000000000..6c37089bd Binary files /dev/null and b/benchmark/allocator differ diff --git a/benchmark/allocator.cpp b/benchmark/allocator.cpp new file mode 100644 index 000000000..7ad46705c --- /dev/null +++ b/benchmark/allocator.cpp @@ -0,0 +1,46 @@ +#include + +#include "utils/memory/allocator.hpp" +#include "utils/memory/maker.hpp" + +struct TestStruct +{ + TestStruct(int a, int b, int c, int d) + : a(a), b(b), c(c), d(d) {} + + int a, b, c, d; +}; + +void test_classic(int N) +{ + TestStruct** xs = new TestStruct*[N]; + + for(int i = 0; i < N; ++i) + xs[i] = new TestStruct(i, i, i, i); + + for(int i = 0; i < N; ++i) + delete xs[i]; + + delete[] xs; +} + +void test_fast(int N) +{ + TestStruct** xs = makeme(N); + + for(int i = 0; i < N; ++i) + xs[i] = makeme(i, i, i, i); + + for(int i = 0; i < N; ++i) + delete xs[i]; + + delete[] xs; +} + +int main(void) +{ + constexpr int N = 20000000; + test_classic(N); + test_fast(N); + return 0; +} diff --git a/data_model/edge.hpp b/data_model/edge.hpp index 56cd32f5e..9531bbbd2 100644 --- a/data_model/edge.hpp +++ b/data_model/edge.hpp @@ -1,16 +1,17 @@ #ifndef MEMGRAPH_DATA_MODEL_EDGE_HPP #define MEMGRAPH_DATA_MODEL_EDGE_HPP -template +#include "json/all.hpp" +#include "record.hpp" + struct Node; -template -struct Edge +struct Edge : Record { + Node* from; + Node* to; - Node* from; - Node* to; - T* data; + json::Object* data; }; #endif diff --git a/data_model/graph.hpp b/data_model/graph.hpp new file mode 100644 index 000000000..b74f73ed9 --- /dev/null +++ b/data_model/graph.hpp @@ -0,0 +1,13 @@ +#ifndef MEMGRAPH_DATA_MODEL_GRAPH_HPP +#define MEMGRAPH_DATA_MODEL_GRAPH_HPP + +#include + +#include "node.hpp" +#include "edge.hpp" + +struct Graph +{ +} + +#endif diff --git a/data_model/node.hpp b/data_model/node.hpp index 5bbe721af..b797f0026 100644 --- a/data_model/node.hpp +++ b/data_model/node.hpp @@ -3,14 +3,16 @@ #include +#include "json/all.hpp" +#include "record.hpp" #include "edge.hpp" -template -struct Node +struct Node : Record { - std::vector*> in; - std::vector*> out; - T* data; + std::vector in; + std::vector out; + + json::Object* data; }; #endif diff --git a/data_model/record.hpp b/data_model/record.hpp new file mode 100644 index 000000000..cffa519d9 --- /dev/null +++ b/data_model/record.hpp @@ -0,0 +1,14 @@ +#ifndef MEMGRAPH_DATA_MODEL_RECORD_HPP +#define MEMGRAPH_DATA_MODEL_RECORD_HPP + +#include + +class Record +{ + uint64_t id; + + // used by MVCC to keep track of what's visible to transactions + uint64_t xmin, xmax; +}; + +#endif diff --git a/data_structures/sllist.hpp b/data_structures/sllist.hpp new file mode 100644 index 000000000..6fd52db84 --- /dev/null +++ b/data_structures/sllist.hpp @@ -0,0 +1,12 @@ +#ifndef MEMGRAPH_DATA_STRUCTURES_SLLIST_HPP +#define MEMGRAPH_DATA_STRUCTURES_SLLIST_HPP + +#include + +template > +class SafeList +{ +}; + +#endif diff --git a/data_structures/spinlock_stack.hpp b/data_structures/slstack.hpp similarity index 100% rename from data_structures/spinlock_stack.hpp rename to data_structures/slstack.hpp diff --git a/test/Makefile b/test/Makefile index d9d91324a..aafc73bd7 100644 --- a/test/Makefile +++ b/test/Makefile @@ -26,4 +26,4 @@ clean: test: make - ./tests --success + ./tests diff --git a/test/allocator.cpp b/test/allocator.cpp new file mode 100644 index 000000000..f6c2b10b6 --- /dev/null +++ b/test/allocator.cpp @@ -0,0 +1,68 @@ +#include "catch.hpp" + +#include "utils/memory/allocator.hpp" + +TEST_CASE("A block of integers can be allocated") +{ + constexpr int N = 100; + + fast_allocator a; + + int* xs = a.allocate(N); + + for(int i = 0; i < N; ++i) + xs[i] = i; + + // can we read them back? + for(int i = 0; i < N; ++i) + REQUIRE(xs[i] == i); + + // we should be able to free the memory + a.deallocate(xs, N); +} + +TEST_CASE("Allocator should work with structures") +{ + struct TestObject + { + TestObject(int a, int b, int c, int d) + : a(a), b(b), c(c), d(d) {} + + int a, b, c, d; + }; + + fast_allocator a; + + SECTION("Allocate a single object") + { + auto* test = a.allocate(1); + *test = TestObject(1, 2, 3, 4); + + REQUIRE(test->a == 1); + REQUIRE(test->b == 2); + REQUIRE(test->c == 3); + REQUIRE(test->d == 4); + + a.deallocate(test, 1); + } + + SECTION("Allocate a block of structures") + { + constexpr int N = 8; + auto* tests = a.allocate(N); + + // structures should not overlap! + for(int i = 0; i < N; ++i) + tests[i] = TestObject(i, i, i, i); + + for(int i = 0; i < N; ++i) + { + REQUIRE(tests[i].a == i); + REQUIRE(tests[i].b == i); + REQUIRE(tests[i].c == i); + REQUIRE(tests[i].d == i); + } + + a.deallocate(tests, N); + } +} diff --git a/test/spinlock.cpp b/test/spinlock.cpp index 2d6519259..fce8592e4 100644 --- a/test/spinlock.cpp +++ b/test/spinlock.cpp @@ -5,8 +5,6 @@ #include "catch.hpp" #include "utils/sync/spinlock.hpp" -#include - TEST_CASE("a thread can acquire and release the lock", "[spinlock]") { SpinLock lock; @@ -30,7 +28,7 @@ void test_lock() x++; REQUIRE(x < 2); - std::this_thread::sleep_for(1s); + std::this_thread::sleep_for(25ms); x--; lock.release(); @@ -38,9 +36,11 @@ void test_lock() TEST_CASE("only one thread at a time can own the lock", "[spinlock]") { + constexpr int N = 64; + std::vector threads; - for(int i = 0; i < 10; ++i) + for(int i = 0; i < N; ++i) threads.push_back(std::thread(test_lock)); for(auto& thread : threads){ diff --git a/utils/memory/allocator.hpp b/utils/memory/allocator.hpp new file mode 100644 index 000000000..b2198b27b --- /dev/null +++ b/utils/memory/allocator.hpp @@ -0,0 +1,51 @@ +#ifndef MEMGRAPH_UTILS_MEMORY_ALLOCATOR_HPP +#define MEMGRAPH_UTILS_MEMORY_ALLOCATOR_HPP + +#include +#include + +template +struct fast_allocator { + typedef Tp value_type; + + fast_allocator() = default; + + template + fast_allocator(const fast_allocator&) {} + + Tp* allocate(std::size_t n); + void deallocate(Tp* p, std::size_t n); +}; + +template +Tp* fast_allocator::allocate(std::size_t n) +{ + // hopefully we're using jemalloc here! + Tp* mem = static_cast(malloc(n * sizeof(Tp))); + + if(mem != nullptr) + return mem; + + throw std::bad_alloc(); +} + +template +void fast_allocator::deallocate(Tp* p, std::size_t) +{ + // hopefully we're using jemalloc here! + free(p); +} + +template +bool operator==(const fast_allocator&, const fast_allocator&) +{ + return true; +} + +template +bool operator!=(const fast_allocator& a, const fast_allocator& b) +{ + return !(a == b); +} + +#endif diff --git a/utils/memory/maker.hpp b/utils/memory/maker.hpp new file mode 100644 index 000000000..0d24f2911 --- /dev/null +++ b/utils/memory/maker.hpp @@ -0,0 +1,27 @@ +#ifndef MEMGRAPH_UTILS_MEMORY_MAKER_HPP +#define MEMGRAPH_UTILS_MEMORY_MAKER_HPP + +#include + +#include "allocator.hpp" + +template > +T* makeme(Args... args) +{ + allocator alloc; + T* mem = alloc.allocate(1); + return new (mem) T(args...); +} + +template > +void takeme(T* mem) +{ + allocator alloc; + mem->~T(); + alloc.deallocate(mem, 1); +} + +#endif