diff --git a/libs/setup.sh b/libs/setup.sh index d18c3d78921..250b2331f6a 100755 --- a/libs/setup.sh +++ b/libs/setup.sh @@ -262,8 +262,8 @@ cd .. absl_ref="20230125.3" repo_clone_try_double "${primary_urls[absl]}" "${secondary_urls[absl]}" "absl" "$absl_ref" -# jemalloc ea6b3e973b477b8061e0076bb257dbd7f3faa756 -JEMALLOC_COMMIT_VERSION="5.2.1" +# jemalloc 54eaed1d8b56b1aa528be3bdd1877e59c56fa90c +JEMALLOC_COMMIT_VERSION="5.3.0" repo_clone_try_double "${primary_urls[jemalloc]}" "${secondary_urls[jemalloc]}" "jemalloc" "$JEMALLOC_COMMIT_VERSION" # this is hack for cmake in libs to set path, and for FindJemalloc to use Jemalloc_INCLUDE_DIR diff --git a/src/memory/global_memory_control.cpp b/src/memory/global_memory_control.cpp index 6073f9d9ac5..a03ae799915 100644 --- a/src/memory/global_memory_control.cpp +++ b/src/memory/global_memory_control.cpp @@ -19,6 +19,8 @@ #if USE_JEMALLOC #include "jemalloc/jemalloc.h" +#else +#include #endif namespace memgraph::memory { @@ -276,6 +278,8 @@ void UnsetHooks() { void PurgeUnusedMemory() { #if USE_JEMALLOC mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", nullptr, nullptr, nullptr, 0); +#else + malloc_trim(0); #endif } diff --git a/src/storage/v2/delta.hpp b/src/storage/v2/delta.hpp index 7e8ac96ac10..f3fb34e4de9 100644 --- a/src/storage/v2/delta.hpp +++ b/src/storage/v2/delta.hpp @@ -69,6 +69,7 @@ struct DeltaMemoryResource : std::pmr::memory_resource { auto earlest_slab_position = alignSize(sizeof(header), alignment); auto max_slab_capacity = PAGE_SIZE - earlest_slab_position; if (max_slab_capacity < bytes) [[unlikely]] { + // dedicated allocation auto required_bytes = bytes + earlest_slab_position; auto *newmem = reinterpret_cast
(aligned_alloc(alignment, required_bytes)); if (!newmem) throw std::bad_alloc{}; @@ -272,20 +273,16 @@ struct Delta { command_id(0), old_disk_key{.value = opt_str{old_disk_key, res}} {} - Delta(DeleteObjectTag /*tag*/, std::atomic *timestamp, uint64_t command_id, - std::pmr::memory_resource * /*res*/) + Delta(DeleteObjectTag /*tag*/, std::atomic *timestamp, uint64_t command_id) : timestamp(timestamp), command_id(command_id), action(Action::DELETE_OBJECT) {} - Delta(RecreateObjectTag /*tag*/, std::atomic *timestamp, uint64_t command_id, - std::pmr::memory_resource * /*res*/) + Delta(RecreateObjectTag /*tag*/, std::atomic *timestamp, uint64_t command_id) : timestamp(timestamp), command_id(command_id), action(Action::RECREATE_OBJECT) {} - Delta(AddLabelTag /*tag*/, LabelId label, std::atomic *timestamp, uint64_t command_id, - std::pmr::memory_resource * /*res*/) + Delta(AddLabelTag /*tag*/, LabelId label, std::atomic *timestamp, uint64_t command_id) : timestamp(timestamp), command_id(command_id), label{.action = Action::ADD_LABEL, .value = label} {} - Delta(RemoveLabelTag /*tag*/, LabelId label, std::atomic *timestamp, uint64_t command_id, - std::pmr::memory_resource * /*res*/) + Delta(RemoveLabelTag /*tag*/, LabelId label, std::atomic *timestamp, uint64_t command_id) : timestamp(timestamp), command_id(command_id), label{.action = Action::REMOVE_LABEL, .value = label} {} Delta(SetPropertyTag /*tag*/, PropertyId key, PropertyValue value, std::atomic *timestamp, @@ -299,25 +296,25 @@ struct Delta { } {} Delta(AddInEdgeTag /*tag*/, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge, std::atomic *timestamp, - uint64_t command_id, std::pmr::memory_resource * /*res*/) + uint64_t command_id) : timestamp(timestamp), command_id(command_id), vertex_edge{.action = Action::ADD_IN_EDGE, .edge_type = edge_type, vertex, edge} {} Delta(AddOutEdgeTag /*tag*/, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge, std::atomic *timestamp, - uint64_t command_id, std::pmr::memory_resource * /*res*/) + uint64_t command_id) : timestamp(timestamp), command_id(command_id), vertex_edge{.action = Action::ADD_OUT_EDGE, .edge_type = edge_type, vertex, edge} {} Delta(RemoveInEdgeTag /*tag*/, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge, std::atomic *timestamp, - uint64_t command_id, std::pmr::memory_resource * /*res*/) + uint64_t command_id) : timestamp(timestamp), command_id(command_id), vertex_edge{.action = Action::REMOVE_IN_EDGE, .edge_type = edge_type, vertex, edge} {} Delta(RemoveOutEdgeTag /*tag*/, EdgeTypeId edge_type, Vertex *vertex, EdgeRef edge, std::atomic *timestamp, - uint64_t command_id, std::pmr::memory_resource * /*res*/) + uint64_t command_id) : timestamp(timestamp), command_id(command_id), vertex_edge{.action = Action::REMOVE_OUT_EDGE, .edge_type = edge_type, vertex, edge} {} diff --git a/src/storage/v2/delta_container.hpp b/src/storage/v2/delta_container.hpp index fe4adf1f393..6ff731d373a 100644 --- a/src/storage/v2/delta_container.hpp +++ b/src/storage/v2/delta_container.hpp @@ -53,9 +53,11 @@ using PageAlignedList = std::forward_list>; template using delta_slab = memgraph::utils::static_vector; -// This is for how many deltas can exist in delta_slab no larger than PAGE_SIZE +// This is for how many deltas can exist in delta_slab no larger than PAGE_SIZE * 4 // assumption `sizeof(void *)` if for the node pointer inside forward_list's node -constexpr auto kMaxDeltas = (PAGE_SIZE - sizeof(void *) - delta_slab<0>::header_size()) / sizeof(Delta); +// We can do 4 pages, because if unused, those pages would +// not contribute to RSS (static_vector ensures buffer in uninitialised) +constexpr auto kMaxDeltas = (PAGE_SIZE * 4 - sizeof(void *) - delta_slab<0>::header_size()) / sizeof(Delta); // Flattern iterators used here becasue we can't use // `std::views::join` becasue stack-use-after-scope @@ -262,13 +264,20 @@ struct delta_container { template auto emplace(Args &&...args) -> Delta & { auto do_emplace = [&]() -> Delta & { - if (!memory_resource_) [[unlikely]] { - // TODO: only do for actions that maybe require allocation - memory_resource_ = std::make_unique(); + if constexpr (std::is_constructible_v) { + // no need for memory_resource + auto &delta = deltas_.front().emplace(std::forward(args)...); + ++size_; + return delta; + } else { + // requires memory_resource + if (!memory_resource_) [[unlikely]] { + memory_resource_ = std::make_unique(); + } + auto &delta = deltas_.front().emplace(std::forward(args)..., memory_resource_.get()); + ++size_; + return delta; } - auto &delta = deltas_.front().emplace(std::forward(args)..., memory_resource_.get()); - ++size_; - return delta; }; if (deltas_.empty() || deltas_.front().is_full()) [[unlikely]] { @@ -290,10 +299,6 @@ struct delta_container { size_ = 0; } - void unlink() { - // Do I move GC code here? - } - bool empty() const { return deltas_.empty(); } auto size() const -> std::size_t { return size_; } diff --git a/src/utils/static_vector.hpp b/src/utils/static_vector.hpp index 15f4890066e..cb84850ace7 100644 --- a/src/utils/static_vector.hpp +++ b/src/utils/static_vector.hpp @@ -106,6 +106,7 @@ struct static_vector { static_vector(static_vector const &other) requires(!std::is_copy_constructible_v) = delete; static_vector &operator=(static_vector const &other) requires(std::is_copy_assignable_v) { + if (this == std::addressof(other)) return *this; auto const b = begin(); auto const ob = other.begin(); if (other.size_ < size_) { @@ -151,7 +152,7 @@ struct static_vector { assert(!is_full()); auto *new_item = &*(begin() + size_); std::construct_at(new_item, std::forward(args)...); - ++size_; // increment after sucessful construction + ++size_; // increment after successful construction return *std::launder(new_item); } @@ -159,7 +160,7 @@ struct static_vector { private: std::size_t size_ = 0; - // deliberatly an uninitialised buffer + // deliberately an uninitialised buffer alignas(alignof(T)) std::byte buffer_[N * sizeof(T)]; };