-
Notifications
You must be signed in to change notification settings - Fork 115
[k2] add separate memory for coroutines #1675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
LLirikkkk
wants to merge
40
commits into
master
Choose a base branch
from
kkotliar/k2_add_coroutine_memory
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
21d42dd
implement coroutine allocator
LLirikkkk e045cfa
apply code style
LLirikkkk c20db9e
move coroutine-allocator into kphp::coro namespace
LLirikkkk aac049c
add noexcept to methods in coroutine-allocator
LLirikkkk 63b65cd
add coroutine-allocator to cmake
LLirikkkk 9699e80
add coroutine malloc interface
LLirikkkk 18e4222
remove excess include in control-block
LLirikkkk 2551c60
rename coroutine-allocator to runtime-coroutine-allocator
LLirikkkk a39d5a9
add std-like wrapper for coroutine-allocator
LLirikkkk ff0826b
add runtime-coroutine-allocator to coroutine-instance-state
LLirikkkk 1303c9f
move coroutines related data to coroutine memory
LLirikkkk 4c409d7
add default values and parsing of args for runtime-coroutine-allocator
LLirikkkk 4654b31
add includes
LLirikkkk 040595a
change default values for memory size
LLirikkkk d5b19ef
enlarge extra-coroutine-memory-pool-size value to 4MB
LLirikkkk d1428ca
small fixes
LLirikkkk 9a1a802
add methods to allocate global memory for coroutines
LLirikkkk ec49ff2
reduce code duplication
LLirikkkk 6f0e11b
add definitions of methods into runtime-allocator
LLirikkkk 3a19375
replace inheritance with composition
LLirikkkk 09af347
add copyright header
LLirikkkk 21678d1
add get_memory_resource method into runtime-allocator and runtime-cor…
LLirikkkk 537e72f
add sources to cmake
LLirikkkk 0b9c6cd
revert replacing script allocator with coroutine allocator in stdlib …
LLirikkkk 9d87104
revert some more changes in stdlib files
LLirikkkk e648ebb
revert some more changes in stdlib files
LLirikkkk 458acc5
small fixes
LLirikkkk 200c531
add global-memory-allocator
LLirikkkk 89e310f
delete redundant file
LLirikkkk 44527e9
fix compilation error
LLirikkkk ecfb23a
replace GlobalMemoryAllocator with free functions
LLirikkkk cc6affb
add sources to cmake
LLirikkkk db7f925
refactor coroutine memory
LLirikkkk 7cb8a7d
fix compilation error
LLirikkkk 6987dca
fix compilation error
LLirikkkk a784e3b
fix compilation error
LLirikkkk bfd4d1a
rename size constants
LLirikkkk 4ad4581
rename size constants
LLirikkkk 848c4ab
fix heap buffer overflow in platfrom malloc interface
LLirikkkk 659ad48
rename arguments in coroutine-state
LLirikkkk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
165 changes: 165 additions & 0 deletions
165
runtime-common/core/allocator/details/malloc-interface.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| // Compiler for PHP (aka KPHP) | ||
| // Copyright (c) 2026 LLC «V Kontakte» | ||
| // Distributed under the GPL v3 License, see LICENSE.notice.txt | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <algorithm> | ||
| #include <cinttypes> | ||
| #include <cstddef> | ||
| #include <cstdint> | ||
| #include <cstring> | ||
| #include <limits> | ||
|
|
||
| #include "common/wrappers/likely.h" | ||
| #include "runtime-common/core/utils/kphp-assert-core.h" | ||
|
|
||
| namespace kphp::memory::details { | ||
|
|
||
| struct control_block { | ||
| private: | ||
| static constexpr auto SIZE_FIELD_BITSIZE{48}; | ||
| static constexpr auto BASE_OFFSET_FIELD_BITSIZE{16}; | ||
| static constexpr uint64_t BLOCK_SIZE_MASK{(1UL << SIZE_FIELD_BITSIZE) - 1}; | ||
| static constexpr uint64_t BASE_OFFSET_MASK{(1UL << BASE_OFFSET_FIELD_BITSIZE) - 1}; | ||
|
|
||
| static_assert(SIZE_FIELD_BITSIZE + BASE_OFFSET_FIELD_BITSIZE == std::numeric_limits<uint64_t>::digits); | ||
|
|
||
| public: | ||
| static constexpr uint64_t max_size() noexcept { | ||
| return 1UL << SIZE_FIELD_BITSIZE; | ||
| } | ||
|
|
||
| static constexpr uint64_t max_alignment() noexcept { | ||
| return 1UL << BASE_OFFSET_FIELD_BITSIZE; | ||
| } | ||
|
|
||
| uint64_t raw() const noexcept { | ||
| return (static_cast<uint64_t>(base_offset) << SIZE_FIELD_BITSIZE) | (static_cast<uint64_t>(size) & BLOCK_SIZE_MASK); | ||
| } | ||
|
|
||
| static control_block from_raw(uint64_t raw) noexcept { | ||
| return control_block{.size = raw & BLOCK_SIZE_MASK, .base_offset = static_cast<uint16_t>((raw >> SIZE_FIELD_BITSIZE) & BASE_OFFSET_MASK)}; | ||
| } | ||
|
|
||
| uint64_t size : SIZE_FIELD_BITSIZE; | ||
| uint16_t base_offset : BASE_OFFSET_FIELD_BITSIZE; | ||
| }; | ||
|
|
||
| inline bool is_power_of_2(uint64_t v) noexcept { | ||
| return v && !(v & (v - 1)); | ||
| } | ||
|
|
||
| static_assert(sizeof(control_block) == sizeof(uint64_t), "Control block's size must be equal to uint64"); | ||
|
|
||
| constexpr uint64_t MALLOC_REPLACER_MAX_ALLOC = 0xFFFFFF00; // 4GiB | ||
|
|
||
| template<auto get_allocator_func> | ||
| struct malloc_interface { | ||
| static auto alloc(size_t size) noexcept -> void* { | ||
| constexpr size_t cb_size{sizeof(kphp::memory::details::control_block)}; | ||
| if (unlikely(size > std::min(kphp::memory::details::control_block::max_size(), MALLOC_REPLACER_MAX_ALLOC) - cb_size)) { | ||
| php_warning("attempt to allocate too much memory by malloc replacer, requested : %lu", size); | ||
| return nullptr; | ||
| } | ||
| const size_t total_size{size + cb_size}; | ||
| void* base{get_allocator_func().alloc_script_memory(total_size)}; | ||
| if (unlikely(base == nullptr)) { | ||
| php_warning("not enough script memory to allocate, requested : %lu, actual requested: %lu", size, total_size); | ||
| return base; | ||
| } | ||
| *(static_cast<uint64_t*>(base)) = kphp::memory::details::control_block{.size = total_size, .base_offset = cb_size}.raw(); | ||
| return static_cast<void*>(static_cast<uint8_t*>(base) + cb_size); | ||
| } | ||
|
|
||
| static auto alloc_aligned(size_t size, std::align_val_t alignment) noexcept -> void* { | ||
| // Check that provided alignment is power of two | ||
| const size_t align{static_cast<uint64_t>(alignment)}; | ||
| if (unlikely(align == 0 || !kphp::memory::details::is_power_of_2(align) || align >= kphp::memory::details::control_block::max_alignment())) { | ||
| php_warning("allocation alignment have to be non-zero power of two and not greater than %" PRIu64 ", got : %lu", | ||
| kphp::memory::details::control_block::max_alignment(), align); | ||
| return nullptr; | ||
| } | ||
|
|
||
| // Check that memory is enough | ||
| constexpr size_t cb_size{sizeof(kphp::memory::details::control_block)}; | ||
| if (unlikely(size > std::min(kphp::memory::details::control_block::max_size(), MALLOC_REPLACER_MAX_ALLOC) - (align - 1) - cb_size)) { | ||
| php_warning("attempt to allocate too much memory by malloc replacer, requested : %lu", size); | ||
| return nullptr; | ||
| } | ||
|
|
||
| // Request mem from underlying memory manager | ||
| const size_t total_size{size + (align - 1) + cb_size}; | ||
| void* base{get_allocator_func().alloc_script_memory(total_size)}; | ||
| if (unlikely(base == nullptr)) { | ||
| php_warning("not enough script memory to allocate, requested : %lu, actual requested: %lu", size, total_size); | ||
| return base; | ||
| } | ||
|
|
||
| const uint64_t base_u{reinterpret_cast<uint64_t>(base)}; | ||
| // The smallest multiple of `align` greater than or equal to requested memory | ||
| const uint64_t aligned_u{((base_u + cb_size) + (align - 1)) & ~(align - 1)}; | ||
| const uint64_t base_offset_u{aligned_u - base_u}; | ||
|
|
||
| // Save control block | ||
| *(reinterpret_cast<uint64_t*>(aligned_u - cb_size)) = // NOLINT | ||
| kphp::memory::details::control_block{.size = total_size, .base_offset = static_cast<std::uint16_t>(base_offset_u)}.raw(); | ||
|
|
||
| return reinterpret_cast<void*>(aligned_u); // NOLINT | ||
| } | ||
|
|
||
| static auto calloc(size_t num, size_t size) noexcept -> void* { | ||
| void* ptr{alloc(num * size)}; | ||
| if (unlikely(ptr == nullptr)) { | ||
| return nullptr; | ||
| } | ||
| return std::memset(ptr, 0, num * size); | ||
| } | ||
|
|
||
| static auto free(void* ptr) noexcept -> void { | ||
| if (unlikely(ptr == nullptr)) { | ||
| return; | ||
| } | ||
|
|
||
| constexpr size_t cb_size{sizeof(kphp::memory::details::control_block)}; | ||
| const auto mem{reinterpret_cast<uint64_t>(ptr)}; | ||
|
|
||
| const auto cb{kphp::memory::details::control_block::from_raw(*reinterpret_cast<uint64_t*>(mem - cb_size))}; // NOLINT | ||
| void* base{reinterpret_cast<void*>(mem - cb.base_offset)}; // NOLINT | ||
|
|
||
| get_allocator_func().free_script_memory(base, cb.size); | ||
| } | ||
|
|
||
| static auto realloc(void* ptr, size_t new_size) noexcept -> void* { | ||
| if (unlikely(ptr == nullptr)) { | ||
| return alloc(new_size); | ||
| } | ||
|
|
||
| if (unlikely(new_size == 0)) { | ||
| free(ptr); | ||
| return nullptr; | ||
| } | ||
|
|
||
| constexpr size_t cb_size{sizeof(kphp::memory::details::control_block)}; | ||
| const auto mem{reinterpret_cast<uint64_t>(ptr)}; | ||
|
|
||
| const auto cb{kphp::memory::details::control_block::from_raw(*reinterpret_cast<uint64_t*>(mem - cb_size))}; // NOLINT | ||
|
|
||
| void* old_base{reinterpret_cast<void*>(mem - cb.base_offset)}; // NOLINT | ||
| const size_t old_size{cb.size}; | ||
|
|
||
| void* new_ptr{alloc(new_size)}; | ||
| if (likely(new_ptr != nullptr)) { | ||
| std::memcpy(new_ptr, ptr, std::min(new_size, old_size)); | ||
| get_allocator_func().free_script_memory(old_base, old_size); | ||
| } | ||
| return new_ptr; | ||
| } | ||
|
|
||
| static auto strdup(const char* str1) noexcept -> char* { | ||
| auto* str2{static_cast<char*>(alloc(std::strlen(str1) + 1))}; | ||
| return std::strcpy(str2, str1); | ||
| } | ||
| }; | ||
|
|
||
| } // namespace kphp::memory::details |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // Compiler for PHP (aka KPHP) | ||
| // Copyright (c) 2026 LLC «V Kontakte» | ||
| // Distributed under the GPL v3 License, see LICENSE.notice.txt | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cstddef> | ||
|
|
||
| #include "common/mixin/not_copyable.h" | ||
| #include "runtime-common/core/memory-resource/unsynchronized_pool_resource.h" | ||
|
|
||
| namespace kphp::memory { | ||
|
|
||
| struct pool_allocator : private vk::not_copyable { | ||
| private: | ||
| memory_resource::unsynchronized_pool_resource memory_resource; | ||
| size_t m_min_extra_mem_size{0}; | ||
|
|
||
| auto request_extra_memory(size_t requested_size) noexcept -> void; | ||
|
|
||
| public: | ||
| pool_allocator() = default; | ||
| pool_allocator(size_t script_mem_size, size_t min_extra_mem_size, size_t oom_handling_mem_size) noexcept; | ||
|
|
||
| auto init(void* buffer, size_t script_mem_size, size_t oom_handling_mem_size) noexcept -> void; | ||
| auto free() noexcept -> void; | ||
|
|
||
| auto alloc(size_t size) noexcept -> void*; | ||
| auto calloc(size_t size) noexcept -> void*; | ||
| auto realloc(void* mem, size_t new_size, size_t old_size) noexcept -> void*; | ||
| auto free(void* mem, size_t size) noexcept -> void; | ||
|
|
||
| auto get_memory_resource() noexcept -> memory_resource::unsynchronized_pool_resource& { | ||
| return memory_resource; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace kphp::memory | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worth making it public
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed