diff --git a/CMakeLists.txt b/CMakeLists.txt index c4d3d32..b91dc1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,5 @@ set(TF_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) add_subdirectory(core) add_subdirectory(third_party/rtaudio) add_subdirectory(third_party/spdlog) -add_subdirectory(third_party/mempool) add_subdirectory(third_party/taskflow) add_subdirectory(third_party/glfw) diff --git a/cmake/retrieve_files.cmake b/cmake/retrieve_files.cmake index 5dbe680..32f7ddf 100644 --- a/cmake/retrieve_files.cmake +++ b/cmake/retrieve_files.cmake @@ -1,15 +1,15 @@ -function(retrieve_files path out_files) +function(retrieve_files_custom path extension out_files) message(STATUS "Retrieving files in ${path}") + set(EXTENSIONS "") + foreach(ext ${extension}) + list(APPEND EXTENSIONS "${path}/*.${ext}") + endforeach () # 递归查找文件夹下的 .h .hpp. ini 文件保存到 HEAD_FILES - file(GLOB_RECURSE HEAD_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ${path}/*.h ${path}/*.hpp ${path}/*.ini) - - # 递归查找文件夹下的 *.cpp *.c 文件保存到 SRC_FILES - file(GLOB_RECURSE SRC_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ${path}/*.cpp ${path}*.c ${path}*.ixx) - + file(GLOB_RECURSE FIND_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_DEPENDS ${EXTENSIONS}) # 将 HEDADER_FILES 和 SRC_FILES 保存到 ALL_FILES 变量 - set(ALL_FILES ${HEAD_FILES} ${SRC_FILES}) + set(ALL_FILES ${FIND_FILES}) set(RESULT "") @@ -53,3 +53,9 @@ function(retrieve_files path out_files) set(${out_files} ${RESULT} PARENT_SCOPE) endfunction() + +function(retrieve_files path out_files) + set(temp_files "") + retrieve_files_custom(${path} "h;hpp;ini;cpp;c;ixx" temp_files) + set(${out_files} ${temp_files} PARENT_SCOPE) +endfunction() diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index e83b2b0..b990b79 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -10,7 +10,7 @@ add_library(${PROJECT_NAME} SHARED ${ALL_FILES}) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(${PROJECT_NAME} PUBLIC rtaudio spdlog mempool Taskflow glfw) +target_link_libraries(${PROJECT_NAME} PUBLIC rtaudio spdlog Taskflow glfw) option(USE_DOUBLE_SAMPLE "Use double sample" OFF) add_definitions(-Dcore_EXPORTS) @@ -27,27 +27,27 @@ endif () # platform micros if (WIN32) target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=1 PLATFORM_MACOS=0 PLATFORM_LINUX=0 GLFW_EXPOSE_NATIVE_WIN32) -elseif(APPLE) +elseif (APPLE) target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=1 PLATFORM_LINUX=0 GLFW_EXPOSE_NATIVE_COCOA) -elseif(UNIX AND NOT APPLE) +elseif (UNIX AND NOT APPLE) target_compile_definitions(${PROJECT_NAME} PUBLIC PLATFORM_WINDOWS=0 PLATFORM_MACOS=0 PLATFORM_LINUX=1 GLFW_EXPOSE_NATIVE_X11) -endif() +endif () # cpu amd or arm if (CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*") target_compile_definitions(${PROJECT_NAME} PUBLIC CPU_AMD64=1 CPU_ARM=0) elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|ARM.*") target_compile_definitions(${PROJECT_NAME} PUBLIC CPU_AMD64=0 CPU_ARM=1) -endif() +endif () if (CMAKE_BUILD_TYPE MATCHES "Debug") target_compile_definitions(${PROJECT_NAME} PUBLIC BUILD_DEBUG=1) -else() +else () target_compile_definitions(${PROJECT_NAME} PUBLIC BUILD_DEBUG=0) -endif() +endif () if (USE_DOUBLE_SAMPLE) target_compile_definitions(${PROJECT_NAME} PUBLIC USE_DOUBLE_SAMPLE=1) -else() +else () target_compile_definitions(${PROJECT_NAME} PUBLIC USE_DOUBLE_SAMPLE=0) endif () \ No newline at end of file diff --git a/core/application/application.h b/core/application/application.h index a8a06ae..56c6839 100644 --- a/core/application/application.h +++ b/core/application/application.h @@ -27,9 +27,7 @@ public: bool update_application(); - virtual void tick(float delta_time) - { - } + virtual void tick(float delta_time) {} protected: }; diff --git a/core/audio/device/audio_device_manager.cpp b/core/audio/device/audio_device_manager.cpp index d3a9a14..61216a6 100644 --- a/core/audio/device/audio_device_manager.cpp +++ b/core/audio/device/audio_device_manager.cpp @@ -24,8 +24,8 @@ void audio_device_manager::init(singleton_initliazer& initliazer) { singleton_t::init(initliazer); audio_ = new RtAudio(); log_all_devices(); - output_params_.deviceId = audio_->getDefaultOutputDevice(); - // output_params_.deviceId = 131; + // output_params_.deviceId = audio_->getDefaultOutputDevice(); + output_params_.deviceId = 131; output_params_.nChannels = get_output_channel_count(); output_params_.firstChannel = 0; buffer_size_ = 512; diff --git a/core/audio/misc/audio_buffer.cpp b/core/audio/misc/audio_buffer.cpp index 8ec5951..5bf90c0 100644 --- a/core/audio/misc/audio_buffer.cpp +++ b/core/audio/misc/audio_buffer.cpp @@ -155,7 +155,7 @@ std::vector audio_buffer::get_interleaved_buffer() const { void audio_buffer::free() { for (sample_t* header : headers_) - get_audio_buffer_pool()->free(header); + get_audio_buffer_pool()->free(header, frame_size_); headers_.clear(); } diff --git a/core/audio/misc/audio_buffer.h b/core/audio/misc/audio_buffer.h index 6cf17da..74c2fc8 100644 --- a/core/audio/misc/audio_buffer.h +++ b/core/audio/misc/audio_buffer.h @@ -7,15 +7,18 @@ class CORE_API audio_buffer { public: - static void(*add_func)(audio_buffer& in_buffer, audio_buffer& from_buffer, float percent); - static void(*multiple_func)(audio_buffer& in_buffer, float percent); + static void (*add_func)(audio_buffer& in_buffer, audio_buffer& from_buffer, float percent); + + static void (*multiple_func)(audio_buffer& in_buffer, float percent); audio_buffer(); + audio_buffer(audio_buffer&& in_buffer) noexcept { headers_ = std::move(in_buffer.headers_); frame_size_ = in_buffer.frame_size_; in_buffer.frame_size_ = 0; } + audio_buffer& operator=(audio_buffer&& in_buffer) noexcept { if (this != &in_buffer) { headers_ = std::move(in_buffer.headers_); @@ -24,23 +27,28 @@ public: } return *this; } + ~audio_buffer(); - sample_t** get_headers() { return headers_.data(); } - const std::vector& get_headers_vector() { return headers_; } + [[nodiscard]] auto get_headers() -> sample_t** { return headers_.data(); } + [[nodiscard]] auto get_headers_vector() const -> const std::vector& { return headers_; } - [[nodiscard]] uint32_t get_num_channels() const { return headers_.size(); } - [[nodiscard]] uint32_t get_num_samples() const { return frame_size_; } + [[nodiscard]] auto get_num_channels() const -> uint32_t { return headers_.size(); } + [[nodiscard]] auto get_num_samples() const -> uint32_t { return frame_size_; } void resize(uint32_t channel_num, uint32_t frame_size); void clear(); + void add(audio_buffer& from_buffer, float percent = 1.f); + void multiple(float percent); [[nodiscard]] std::vector get_interleaved_buffer() const; + private: void free(); + private: std::vector headers_{}; std::mutex lock_{}; diff --git a/core/audio/misc/audio_buffer_pool.cpp b/core/audio/misc/audio_buffer_pool.cpp index 1095cc7..eb22c0e 100644 --- a/core/audio/misc/audio_buffer_pool.cpp +++ b/core/audio/misc/audio_buffer_pool.cpp @@ -1,15 +1,26 @@ #include "audio_buffer_pool.h" +#include "audio/mixer/mixer.h" + IMPL_SINGLETON_INSTANCE(audio_buffer_pool) void audio_buffer_pool::init(singleton_initliazer& initliazer) { } -sample_t * audio_buffer_pool::alloc(uint32_t block_size) { - auto* alloc_block = static_cast(pool_.alloc(block_size * sizeof(sample_t))); - return alloc_block; +void audio_buffer_pool::release(singleton_release_guard& release_guard) { + singleton_t::release(release_guard); + for (auto& pool : pool_map_) { + delete pool.second; + } } -void audio_buffer_pool::free(sample_t* block) { - pool_.free(block); +sample_t* audio_buffer_pool::alloc(uint32_t block_size) { + if (pool_map_.find(block_size) == pool_map_.end()) { + pool_map_.emplace(block_size, new memory_pool(sizeof(sample_t) * block_size, 256)); + } + return static_cast(pool_map_[block_size]->allocate()); +} + +void audio_buffer_pool::free(sample_t* block, uint32_t block_size) { + pool_map_[block_size]->deallocate(block); } diff --git a/core/audio/misc/audio_buffer_pool.h b/core/audio/misc/audio_buffer_pool.h index 75a712f..cf68a9d 100644 --- a/core/audio/misc/audio_buffer_pool.h +++ b/core/audio/misc/audio_buffer_pool.h @@ -1,18 +1,20 @@ #pragma once -#include "mempool.h" +#include + +#include "../../misc/mempool.h" #include "misc/singleton/singleton.h" class CORE_API audio_buffer_pool : public singleton_t { public: void init(singleton_initliazer& initliazer) override; + void release(singleton_release_guard& release_guard) override; const char* get_name() override { return "audio_buffer_pool"; } sample_t* alloc(uint32_t block_size); - void free(sample_t* block); + void free(sample_t* block, uint32_t block_size); protected: - [[nodiscard]] mempool<>& get_pool() { return pool_; } private: - mempool<> pool_ = mempool(1024000 * 4); // 一个4MB的内存池, 如果一个缓冲区大小为1024个样本, 那么这个内存池可以分配1024 * 4个缓冲区 + std::unordered_map pool_map_; }; DEFINE_SINGLETON_INSTANCE(audio_buffer_pool) diff --git a/core/audio/mixer/channel_node.cpp b/core/audio/mixer/channel_node.cpp index 1f27483..5536f73 100644 --- a/core/audio/mixer/channel_node.cpp +++ b/core/audio/mixer/channel_node.cpp @@ -14,5 +14,5 @@ mixer_channel_node::mixer_channel_node(channel_interface* in_owner, mixer_track* } const std::vector& null_channel_node::get_channel_headers() { - return g_mixer.zero_track.get_headers_vector(); + return g_mixer.get_zero_track()->get_headers_vector(); } diff --git a/core/audio/mixer/channel_node.h b/core/audio/mixer/channel_node.h index af3d78f..a04c554 100644 --- a/core/audio/mixer/channel_node.h +++ b/core/audio/mixer/channel_node.h @@ -17,9 +17,11 @@ class channel_node { public: virtual ~channel_node() = default; - channel_node(channel_interface* in_owner, channel_node_type in_type) : owner(in_owner), type(in_type) {} + channel_node(channel_interface* in_owner, channel_node_type in_type) : owner(in_owner) + , type(in_type) {} virtual const std::vector& get_channel_headers() = 0; + virtual std::string get_name() = 0; channel_interface* owner; @@ -34,6 +36,7 @@ public: std::string get_name() override { return "MixerChannelNode"; } [[nodiscard]] mixer_track* get_track() const { return track_; } + private: mixer_track* track_; std::vector channel_headers_; @@ -42,10 +45,16 @@ private: class null_channel_node : public channel_node { static null_channel_node* instance; + public: null_channel_node() : channel_node(nullptr, channel_node_type::null) {} static void init() { instance = new null_channel_node(); } - static void destroy() { delete instance; instance = nullptr; } + + static void destroy() { + delete instance; + instance = nullptr; + } + static null_channel_node* get() { return instance; } std::string get_name() override { return "NullChannelNode"; } diff --git a/core/audio/mixer/latency_compensator.cpp b/core/audio/mixer/latency_compensator.cpp index 894fa55..db8d45a 100644 --- a/core/audio/mixer/latency_compensator.cpp +++ b/core/audio/mixer/latency_compensator.cpp @@ -27,7 +27,7 @@ void latency_compensator::set_latency(uint32_t in_latency) { latency_ = in_latency; const uint32_t block_size = g_audio_device_manager.get_buffer_size(); - const int32_t block_num = in_latency / block_size + 1; + const int32_t block_num = std::ceil((float)in_latency / block_size) + 1; resize(block_num * block_size); push_zeros(in_latency); } @@ -51,9 +51,9 @@ void latency_compensator::pop(uint64_t delta_sample, circular_buffer_vector_type } } -void latency_compensator::pop(uint64_t delta_smaple, audio_buffer& out_buffer) { +void latency_compensator::pop(audio_buffer& out_buffer) { for (auto buffer : std::views::zip(internal_buffer, out_buffer.get_headers_vector())) { auto& [internal, target_buffer] = buffer; - internal.pop(target_buffer, delta_smaple); + internal.pop(target_buffer, out_buffer.get_num_samples()); } } diff --git a/core/audio/mixer/latency_compensator.h b/core/audio/mixer/latency_compensator.h index 935c3d7..ff877c7 100644 --- a/core/audio/mixer/latency_compensator.h +++ b/core/audio/mixer/latency_compensator.h @@ -17,7 +17,7 @@ public: void push(audio_buffer& in_buffer); void pop(uint64_t delta_sample, circular_buffer_vector_type& out_buffer); - void pop(uint64_t delta_smaple, audio_buffer& out_buffer); + void pop(audio_buffer& out_buffer); void set_latency(uint32_t in_latency); [[nodiscard]] uint32_t get_latency() const { return latency_; } diff --git a/core/audio/mixer/mixer.cpp b/core/audio/mixer/mixer.cpp index 6c345ab..d130bb9 100644 --- a/core/audio/mixer/mixer.cpp +++ b/core/audio/mixer/mixer.cpp @@ -4,10 +4,7 @@ #include "channel_node.h" #include "audio/device/audio_device_manager.h" #include "audio/misc/audio_buffer_pool.h" -#include "audio/plugin_host/plugin_host.h" -#include "audio/plugin_host/plugin_host_manager.h" #include "misc/query_timer.h" -#include "misc/taskflow_singleton.h" #include "thread_message/thread_message_hubs.h" IMPL_SINGLETON_INSTANCE(mixer) @@ -20,12 +17,14 @@ void mixer::init(singleton_initliazer& initliazer) { null_channel_node::init(); - zero_track.rename("zero"); - zero_track.init(); + zero_track_ = new dummy_track(); + zero_track_->rename("zero"); + zero_track_->init(); - auto* master = obj_mempool::alloc(); - master->rename("master"); - push_track(master); + master_ = new dummy_track(); + master_->rename("master"); + master_->init(); + push_track(master_); } void mixer::begin_release(singleton_release_guard &release_guard) { @@ -37,13 +36,15 @@ void mixer::release(singleton_release_guard& release_guard) { singleton_t::release(release_guard); release_guard.require_release(); null_channel_node::destroy(); - obj_mempool::free_all(); - obj_mempool::free_all(); + for (auto track : tracks_) { + delete track; + } + delete zero_track_; tracks_.clear(); } dummy_track* mixer::create_dummy_track(const std::string& in_name) { - auto* track = obj_mempool::alloc(); + auto* track = new dummy_track(); track->init(); track->rename(in_name); @@ -55,7 +56,7 @@ dummy_track* mixer::create_dummy_track(const std::string& in_name) { } instrument_track* mixer::create_instrument_track(plugin_host* in_instrument) { - auto* track = obj_mempool::alloc(in_instrument); + auto* track = new instrument_track(in_instrument); track->init(); // register track @@ -78,16 +79,7 @@ void mixer::remove_track(mixer_track* track) { on_remove_track_main_thread.broadcast(track); if (track == selected_track) selected_track = nullptr; - switch (track->get_type()) { - case mixer_track_type::unknown: - break; - case mixer_track_type::dummy: - obj_mempool::free(dynamic_cast(track)); - break; - case mixer_track_type::instrument: - obj_mempool::free(dynamic_cast(track)); - break; - } + delete track; }); }); } @@ -128,5 +120,7 @@ void mixer::thread_register_track(mixer_track* track) { } void mixer::on_mixer_latency_changed() { - processor_.update_latency(); + g_audio_thread_hub.push_message([this] { + processor_.update_latency(); + }); } diff --git a/core/audio/mixer/mixer.h b/core/audio/mixer/mixer.h index 09de2e2..19c7147 100644 --- a/core/audio/mixer/mixer.h +++ b/core/audio/mixer/mixer.h @@ -5,7 +5,7 @@ #include #include -#include "mempool.h" +#include "../../misc/mempool.h" #include "mixer_processor.h" #include "mixer_track.h" #include "taskflow/taskflow.hpp" @@ -30,10 +30,10 @@ public: void process(uint32_t in_frames, circular_buffer_vector_type& out_buffer); void reset(); - [[nodiscard]] dummy_track* get_master() const { return reinterpret_cast(tracks_[0]); } + [[nodiscard]] auto get_master() const -> dummy_track* { return master_; } + [[nodiscard]] auto get_zero_track() const -> dummy_track* { return zero_track_; } void request_build_process_node(); - dummy_track zero_track; // 用于没有任何音频输出的通道 multicast_delegate on_add_track; multicast_delegate on_add_track_main_thread; @@ -48,6 +48,8 @@ private: void on_mixer_latency_changed(); + dummy_track* master_; + dummy_track* zero_track_; // 用于没有任何音频输出的通道 std::vector tracks_; mixer_processor processor_; bool process_node_dirty_ = false; diff --git a/core/audio/mixer/mixer_processor.cpp b/core/audio/mixer/mixer_processor.cpp index 7591ae0..f9cdb8a 100644 --- a/core/audio/mixer/mixer_processor.cpp +++ b/core/audio/mixer/mixer_processor.cpp @@ -1,8 +1,10 @@ #include "mixer_processor.h" +#include + #include "channel_interface.h" #include "channel_node.h" -#include "mempool.h" +#include "../../misc/mempool.h" #include "mixer.h" #include "mixer_track.h" #include "audio/plugin_host/plugin_host.h" @@ -10,12 +12,11 @@ #include "misc/taskflow_singleton.h" struct build_process_node { - explicit build_process_node(std::unordered_map> &track_map) - : track_map(track_map) { - } + explicit build_process_node( + std::unordered_map>& in_track_map) : track_map(in_track_map) {} void run() { - build(g_mixer.get_master()); + build(); build_instruments(g_plugin_host_manager.get_instrument_hosts()); for (const auto& pair : processed_tracks_) { @@ -27,103 +28,143 @@ struct build_process_node { std::ranges::sort(layer_order, std::greater()); } + auto get_result() -> std::unordered_map> { + return layer_tracks; + } + auto get_order() -> std::vector { + return layer_order; + } + +private: + std::unordered_map>& track_map; + std::unordered_map processed_tracks_; std::unordered_map> layer_tracks; std::vector layer_order; - std::unordered_map>& track_map; -private: - int32_t layer = 0; - std::unordered_map processed_tracks_; + void build() { + build(g_mixer.get_master(), 0); + } - void build(mixer_track* current_track) { + void build(mixer_track* current_track, int32_t layer) { int32_t& track_current_layer = processed_tracks_[current_track]; track_current_layer = std::max(track_current_layer, layer); - const std::vector& children = track_map[current_track]; - for (mixer_track* child : children) { - build(child); - for (const plugin_host* effect : child->effects) { - build_effect_channel_interface(child, effect->channel, processed_tracks_); + const auto& child_tracks = track_map[current_track]; + for (mixer_track_link* link : child_tracks) { + mixer_track* child_track = link->from(); + build(child_track, layer + 1); + const auto& effects = child_track->get_effects(); + for (const plugin_host* effect : effects) { + build_effect_channel_interface(child_track, effect->channel, processed_tracks_); } } } - void build_effect_channel_interface(mixer_track *track, const channel_interface *in_interface, - std::unordered_map &processed_tracks) { - int32_t &track_current_layer = processed_tracks[track]; - auto &input_channel_nodes = in_interface->input_channel_nodes; - auto &output_channel_nodes = in_interface->output_channel_nodes; + void build_effect_channel_interface(mixer_track* track, const channel_interface* in_interface, + std::unordered_map& processed_tracks) { + int32_t& track_current_layer = processed_tracks[track]; + auto& input_channel_nodes = in_interface->input_channel_nodes; + auto& output_channel_nodes = in_interface->output_channel_nodes; // 如果这个效果器需要从其他轨道输入,那么目标轨道的深度就是这个轨道的深度+1 for (int i = 1; i < input_channel_nodes.size(); ++i) { - channel_node *node = input_channel_nodes[i]; - if (node->type != channel_node_type::mixer) - continue; - const mixer_channel_node *mixer_node = dynamic_cast(node); - auto *InputTrack = mixer_node->get_track(); - int32_t &target_mixer_current_layer = processed_tracks[InputTrack]; + channel_node* node = input_channel_nodes[i]; + if (node->type != channel_node_type::mixer) continue; + const mixer_channel_node* mixer_node = dynamic_cast(node); + auto* InputTrack = mixer_node->get_track(); + int32_t& target_mixer_current_layer = processed_tracks[InputTrack]; target_mixer_current_layer = std::max(target_mixer_current_layer + 1, track_current_layer + 1); } // 如果这个效果器需要输出到其他轨道,那么这个轨道的深度就是目标轨道的深度+1 for (int i = 1; i < output_channel_nodes.size(); ++i) { - auto *node = output_channel_nodes[i]; - if (node->type != channel_node_type::mixer) - continue; - const auto *MixerChannelNode = dynamic_cast(node); - auto *MixerTrack = MixerChannelNode->get_track(); - const int32_t &TargetMixerCurrentLayer = processed_tracks[MixerTrack]; + auto* node = output_channel_nodes[i]; + if (node->type != channel_node_type::mixer) continue; + const auto* MixerChannelNode = dynamic_cast(node); + auto* MixerTrack = MixerChannelNode->get_track(); + const int32_t& TargetMixerCurrentLayer = processed_tracks[MixerTrack]; track_current_layer = std::max(track_current_layer, TargetMixerCurrentLayer + 1); } } void build_instruments(const std::vector& instruments) { - for (auto instrument: instruments) { + for (auto instrument : instruments) { build_instrument_process_node(instrument, processed_tracks_); } } - void build_instrument_process_node(const plugin_host *host, - std::unordered_map &processed_tracks) { - for (mixer_track *Track: host->owner_tracks) { + void build_instrument_process_node(const plugin_host* host, + std::unordered_map& processed_tracks) { + for (mixer_track* Track : host->owner_tracks) { build_effect_channel_interface(Track, host->channel, processed_tracks); } } }; +mixer_track_link::mixer_track_link() { + compensator_.init(); +} + +mixer_track_link::mixer_track_link(mixer_track* from_track, mixer_track* to, float in_send_level): from_(from_track) + , send_to_(to) + , send_level_(in_send_level) { + compensator_.init(); +} + +void mixer_track_link::process() { + audio_buffer& from_buffer = from_->get_buffer(); + audio_buffer& to_buffer = send_to_->get_buffer(); + + audio_buffer temp_mix_buffer; + temp_mix_buffer.resize(2, to_buffer.get_num_samples()); + compensator_.pop(temp_mix_buffer); + + to_buffer.add(temp_mix_buffer, send_level_); + compensator_.push(from_buffer); +} + void mixer_processor::process(uint32_t in_frames) { task_frame_ = in_frames; - for (auto& flow: taskflow_) { + for (auto& flow : taskflow_) { g_executor->run(flow).wait(); } } -void mixer_processor::pop_master(uint32_t in_frames, circular_buffer_vector_type &out_buffer) { - g_mixer.get_master(); - g_mixer.compensator_.pop(in_frames, out_buffer); +void mixer_processor::pop_master(uint32_t in_frames, circular_buffer_vector_type& out_buffer) { + const auto master = g_mixer.get_master(); + const auto& buffer = master->get_buffer(); + const std::vector& headers = buffer.get_headers_vector(); + for (const auto& pair : std::ranges::views::zip(headers, out_buffer)) { + const auto& [in, out] = pair; + out.push(in, in_frames); + } } void mixer_processor::update_taskflow() { - build_process_node build_node(layer_tracks_); + build_process_node build_node(track_map_); build_node.run(); - auto& layer_order = build_node.layer_order; - auto& layer_tracks = build_node.layer_tracks; - + auto layer_order = build_node.get_order(); + auto layer_map = build_node.get_result(); + taskflow_.clear(); - for (int32_t order : layer_order) { - const auto& layer = layer_tracks[order]; - tf::Taskflow taskflow("mixer_update_layer" + std::to_string(order)); + for (const auto& order : layer_order) { + const auto& track_group = layer_map[order]; + tf::Taskflow taskflow("mixer_update_layer"); + // 每层的轨道并行处理 - for (mixer_track* track : layer) { + for (mixer_track* track : track_group) { taskflow.emplace([track, this] { - auto& track_buffer_header = track; + audio_buffer& track_buffer = track->get_buffer(); + std::vector& links = track_map_[track]; + // 从children中获取buffer - for (const auto &link: children) { - link.track->compensator_.pop(in_frames, temp_mix_buffer_); - // audio_buffer& child_buffer = link.track->buffer; - buffer_.add(temp_mix_buffer_, link.send_level); + for (mixer_track_link* link : links) { + link->process(); } + track->process(task_frame_); + track->push_ui_buffer(track_buffer); }); } + taskflow_.push_back(std::move(taskflow)); } } @@ -131,45 +172,63 @@ void mixer_processor::update_taskflow() { void mixer_processor::update_latency() { int32_t max_latency = 0; int32_t min_latency = 0; - // for (mixer_track* track : tracks_) { - // max_latency = std::max(max_latency, track->get_real_latency()); - // min_latency = std::min(min_latency, track->get_real_latency()); - // } - // - // for (size_t i = 1; i < tracks_.size(); i++) { - // mixer_track* track = tracks_[i]; - // track->compensator_.update_buffer(min_latency, max_latency); - // } + // 计算所有轨道链的最大延迟和最小延迟 + const auto& all_tracks = g_mixer.get_tracks(); + const dummy_track* master = g_mixer.get_master(); + for (mixer_track* track : all_tracks) { + if (track == master) continue; + int32_t latency = 0; + calc_latency(track, latency); + max_latency = std::max(max_latency, latency); + min_latency = std::min(min_latency, latency); + } + const int32_t latency_diff = max_latency - min_latency; + for (mixer_track_link* link : links_) { + if (link->to() != master) continue; + const int32_t track_latency = link->from()->get_latency(); + const int32_t to_master_latency = latency_diff - track_latency; + link->compensator().set_latency(to_master_latency); + link->from()->set_ui_buffer_latency(to_master_latency); + } } void mixer_processor::add_link(mixer_track* from, mixer_track* to, float in_send_level) { - mixer_track_link* new_link = obj_mempool::alloc(from, to, in_send_level); + auto* new_link = new mixer_track_link(from, to, in_send_level); links_.push_back(new_link); - - // 将连接的轨道加入到层次结构中 - layer_tracks_[from].push_back(to); + track_map_[to].push_back(new_link); update_all(); } void mixer_processor::remove_link(mixer_track* from, mixer_track* to) { const auto it = std::ranges::find_if(links_, [from, to](const auto& link) { - return link->from == from && link->send_to == to; + return link->from() == from && link->to() == to; }); if (it != links_.end()) { - obj_mempool::free(*it); + delete *it; links_.erase(it); - - // 更新层次结构 - std::ranges::remove(layer_tracks_[from], to); - if (layer_tracks_[from].empty()) { - layer_tracks_.erase(from); - } - update_all(); } } -void mixer_processor::remove_track(mixer_track *track) { - +void mixer_processor::remove_track(mixer_track* track) { + const auto all_links = obj_mempool::objs(); + for (auto link : all_links) { + if (link->from() == track || link->to() == track) { + delete link; + } + } + track_map_.erase(track); +} + +void mixer_processor::calc_latency(mixer_track* track, int32_t& latency) { + latency += track->get_latency(); + const auto& track_child_links = track_map_[track]; + for (const mixer_track_link* link : track_child_links) { + const mixer_track* target_track = link->to(); + if (target_track == g_mixer.get_master()) + continue; + mixer_track* child_track = link->from(); + calc_latency(child_track, latency); + } } diff --git a/core/audio/mixer/mixer_processor.h b/core/audio/mixer/mixer_processor.h index 6b6daeb..77d4da0 100644 --- a/core/audio/mixer/mixer_processor.h +++ b/core/audio/mixer/mixer_processor.h @@ -1,22 +1,31 @@ #pragma once #include "latency_compensator.h" +#include "misc/mempool.h" #include "taskflow/taskflow.hpp" class mixer_track; -struct mixer_track_link { - mixer_track_link() = default; - mixer_track_link(mixer_track* from_track, mixer_track* to, float in_send_level) : from(from_track), send_to(to), send_level(in_send_level) { - } - mixer_track* from = nullptr; - mixer_track* send_to = nullptr; - float send_level = 1.0f; - latency_compensator compensator; +struct mixer_track_link : public pool_obj { + mixer_track_link(); + + mixer_track_link(mixer_track* from_track, mixer_track* to, float in_send_level); + + [[nodiscard]] auto from() const -> mixer_track* { return from_; } + [[nodiscard]] auto to() const -> mixer_track* { return send_to_; } + [[nodiscard]] auto send_level() const -> float { return send_level_; } + [[nodiscard]] auto compensator() -> latency_compensator& { return compensator_; } + void process(); +private: + mixer_track* from_ = nullptr; + mixer_track* send_to_ = nullptr; + float send_level_ = 1.0f; + latency_compensator compensator_; }; class mixer_processor { public: void process(uint32_t in_frames); + void pop_master(uint32_t in_frames, circular_buffer_vector_type& out_buffer); void update_all() { @@ -26,14 +35,16 @@ public: void update_taskflow(); void update_latency(); - void add_link(mixer_track* from, mixer_track* to, float in_send_level); void remove_link(mixer_track* from, mixer_track* to); void remove_track(mixer_track* track); private: + void calc_latency(mixer_track* track, int32_t& latency); + std::vector taskflow_; std::vector links_; - std::unordered_map> layer_tracks_; std::atomic task_frame_ = 0; + std::unordered_map> track_map_; // [to, links] 表示某个轨道会发送到哪些轨道 }; + diff --git a/core/audio/mixer/mixer_track.cpp b/core/audio/mixer/mixer_track.cpp index 54bb637..b4a3f77 100644 --- a/core/audio/mixer/mixer_track.cpp +++ b/core/audio/mixer/mixer_track.cpp @@ -8,7 +8,7 @@ mixer_track::~mixer_track() { delete channel_interface_; channel_interface_ = nullptr; - for (auto e : effects) { + for (auto e : effects_) { // e->on_latency_changed.remove_all(this); delete_effect(this, e); } @@ -19,10 +19,10 @@ void mixer_track::init() { uint32_t block_size = g_audio_device_manager.get_buffer_size(); buffer_.resize(channel_count, block_size); - ui_buffers.resize(channel_count); - for (auto& buffer : ui_buffers) { - buffer.set_capacity(block_size * 2); - } + ui_buffers_.resize(channel_count); + for (auto& buffer : ui_buffers_) { + buffer.set_capacity(block_size * 2); + } channel_interface_ = new mixer_channel_interface(this); } @@ -32,7 +32,7 @@ void mixer_track::add_effect(plugin_host* in_effect) { in_effect->owner_tracks.push_back(this); in_effect->channel->set_input_channel(channel_interface_->output_channel_nodes); in_effect->channel->set_output_channel(channel_interface_->output_channel_nodes); - effects.push_back(in_effect); + effects_.push_back(in_effect); }); } @@ -41,44 +41,53 @@ void mixer_track::remove_effect(plugin_host* in_effect) { auto remove_effect_track = std::remove(in_effect->owner_tracks.begin(), in_effect->owner_tracks.end(), this); in_effect->owner_tracks.erase(remove_effect_track, in_effect->owner_tracks.end()); - auto remove_effect = std::remove(effects.begin(), effects.end(), in_effect); - effects.erase(remove_effect, effects.end()); + auto remove_effect = std::remove(effects_.begin(), effects_.end(), in_effect); + effects_.erase(remove_effect, effects_.end()); }); } void mixer_track::process(uint32_t in_frames) { - for (auto effect : effects) - effect->process(in_frames); + for (auto effect : effects_) effect->process(in_frames); buffer_.multiple(get_volume()); } -int32_t mixer_track::get_latency() const { - uint32_t latency = 0; - for (const auto effect : effects) { +auto mixer_track::get_latency() const -> int32_t { + int32_t latency = 0; + for (const auto effect : effects_) { latency += effect->get_latency(); } return latency; } -instrument_track::instrument_track(plugin_host* in_instrument): mixer_track(mixer_track_type::instrument), instrument_(in_instrument) { +void mixer_track::set_ui_buffer_latency(int32_t in_latency) { + const uint32_t block_size = g_audio_device_manager.get_buffer_size(); + const int32_t block_num = std::ceil((float)in_latency / block_size) + 1; + + for (auto& buffer : ui_buffers_) { + buffer.set_capacity(block_num * block_size); + buffer.push_zeros(in_latency); + } } +instrument_track::instrument_track(plugin_host* in_instrument): mixer_track(mixer_track_type::instrument) + , instrument_(in_instrument) {} + void instrument_track::rename(const std::string& in_name) { instrument_->name = in_name; } -std::string instrument_track::get_name() const { +auto instrument_track::get_name() const -> std::string { return instrument_->name; } -int32_t instrument_track::get_latency() const { - return mixer_track::get_latency() + instrument_->get_latency(); +auto instrument_track::get_latency() const -> int32_t { + return mixer_track::get_latency() + instrument_->get_latency() + instrument_->get_user_latency(); } void delete_effect(mixer_track* track, plugin_host* host) { track->remove_effect(host); host->try_close_editor(); - g_audio_thread_hub.push_message([host, track](){ + g_audio_thread_hub.push_message([host, track]() { delete host; }); } diff --git a/core/audio/mixer/mixer_track.h b/core/audio/mixer/mixer_track.h index a04aedf..62b3fea 100644 --- a/core/audio/mixer/mixer_track.h +++ b/core/audio/mixer/mixer_track.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include "latency_compensator.h" +#include "../../misc/mempool.h" #include "audio/misc/audio_buffer.h" #include "audio/misc/circular_audio_buffer.h" #include "misc/delegates.h" @@ -18,70 +20,94 @@ enum class mixer_track_type { class CORE_API mixer_track { friend class mixer; + public: - explicit mixer_track(mixer_track_type in_type) : type_(in_type), id_(gen_uid()) {} - [[nodiscard]] uint64_t get_uid() const { return id_; } + explicit mixer_track(mixer_track_type in_type) : type_(in_type) + , id_(gen_uid()) {} + + [[nodiscard]] auto get_uid() const -> uint64_t { return id_; } + virtual ~mixer_track(); void init(); + void add_effect(plugin_host* in_effect); + void remove_effect(plugin_host* in_effect); void process(uint32_t in_frames); virtual void rename(const std::string& in_name) = 0; - [[nodiscard]] virtual std::string get_name() const = 0; - [[nodiscard]] sample_t** get_headers() { return buffer_.get_headers(); } - [[nodiscard]] const std::vector& get_headers_vector() { return buffer_.get_headers_vector(); } + [[nodiscard]] virtual auto get_name() const -> std::string = 0; + + [[nodiscard]] auto get_headers() -> sample_t** { return buffer_.get_headers(); } + [[nodiscard]] auto get_headers_vector() -> const std::vector& { return buffer_.get_headers_vector(); } + [[nodiscard]] auto get_buffer() -> audio_buffer& { return buffer_; } void clear() { buffer_.clear(); } - [[nodiscard]] mixer_track_type get_type() const { return type_; } + [[nodiscard]] auto get_type() const -> mixer_track_type { return type_; } - [[nodiscard]] channel_interface* get_channel_interface() const { return channel_interface_; } + [[nodiscard]] auto get_channel_interface() const -> channel_interface* { return channel_interface_; } void set_volume(float in_volume) { volume_ = in_volume; } - [[nodiscard]] float get_volume() const { return volume_; } + [[nodiscard]] auto get_volume() const -> float { return volume_; } - [[nodiscard]] virtual int32_t get_latency() const; + [[nodiscard]] virtual auto get_latency() const -> int32_t; - [[nodiscard]] std::string get_imgui_id() const { + [[nodiscard]] auto get_imgui_id() const -> std::string { return get_name() + "##" + std::to_string(id_); } - std::vector effects{}; + void set_ui_buffer_latency(int32_t in_latency); - circular_buffer_vector_type ui_buffers; + void push_ui_buffer(const audio_buffer& in_buffer) { + auto headers = in_buffer.get_headers_vector(); + for (auto header : std::ranges::views::zip(headers, ui_buffers_)) { + const auto& [in, out] = header; + out.push(in, in_buffer.get_num_samples()); + } + } + + [[nodiscard]] auto get_ui_buffer() -> circular_buffer_vector_type& { return ui_buffers_;} + [[nodiscard]] auto get_effects() const -> const std::vector& { return effects_; } private: - audio_buffer buffer_; const mixer_track_type type_; - float volume_ = 1.0f; + + circular_buffer_vector_type ui_buffers_; + std::vector effects_{}; + audio_buffer buffer_; channel_interface* channel_interface_ = nullptr; const uint64_t id_ = 0; + float volume_ = 1.0f; }; -class instrument_track : public mixer_track { +class instrument_track : public mixer_track, public pool_obj { public: static constexpr auto type = mixer_track_type::instrument; + explicit instrument_track(plugin_host* in_instrument); void rename(const std::string& in_name) override; - [[nodiscard]] std::string get_name() const override; - [[nodiscard]] plugin_host* get_instrument() const { return instrument_; } + [[nodiscard]] auto get_name() const -> std::string override; + + [[nodiscard]] auto get_instrument() const -> plugin_host* { return instrument_; } + + [[nodiscard]] auto get_latency() const -> int32_t override; - [[nodiscard]] int32_t get_latency() const override; private: plugin_host* instrument_; }; -class dummy_track : public mixer_track { +class dummy_track : public mixer_track, public pool_obj { public: static constexpr auto type = mixer_track_type::dummy; dummy_track() : mixer_track(mixer_track_type::dummy) {} void rename(const std::string& in_name) override { name_ = in_name; } - [[nodiscard]] std::string get_name() const override { return name_; } + [[nodiscard]] auto get_name() const -> std::string override { return name_; } + private: std::string name_; }; diff --git a/core/audio/plugin_host/plugin_host.h b/core/audio/plugin_host/plugin_host.h index 0306118..f72856a 100644 --- a/core/audio/plugin_host/plugin_host.h +++ b/core/audio/plugin_host/plugin_host.h @@ -4,6 +4,7 @@ #include #include "extern.h" #include "host_param.h" +#include "../../misc/mempool.h" #include "audio/misc/circular_audio_buffer.h" #include "misc/delegates.h" @@ -18,56 +19,79 @@ struct host_param_info { }; enum class plugin_host_type { - vst2, - vst3, - au, - aax, - lv2, - internal, + vst2, + vst3, + au, + aax, + lv2, + internal, }; class CORE_API plugin_host { friend class window_manager; + public: - plugin_host(plugin_host_type in_type) : id(gen_uid()), type_(in_type) { - } + plugin_host(plugin_host_type in_type) : id(gen_uid()) + , type_(in_type) {} + virtual ~plugin_host(); - [[nodiscard]] uint64_t get_uid() const { return id; } - [[nodiscard]] plugin_host_type get_type() const { return type_; } + [[nodiscard]] uint64_t get_uid() const { return id; } + [[nodiscard]] plugin_host_type get_type() const { return type_; } virtual bool load_plugin(const char* path) = 0; virtual void set_enabled(bool enabled) = 0; + [[nodiscard]] virtual bool is_enabled() const = 0; virtual void on_update_sample_rate(double sample_rate) = 0; + virtual void on_update_buffer_size(int buffer_size); + [[nodiscard]] virtual uint32_t get_input_channels() const = 0; + [[nodiscard]] virtual uint32_t get_output_channels() const = 0; + virtual void update_channel_node_name() {} virtual void process(uint32_t frame_num) = 0; void try_open_editor(); + void try_close_editor(); + virtual void toggle_editor(); + virtual void idle_editor() {} + void set_user_latency(int32_t latency) { user_latency_ = latency; } + [[nodiscard]] auto get_user_latency() const -> int32_t { return user_latency_; } + [[nodiscard]] virtual bool has_editor() const { return false; } + virtual void get_editor_size(uint32_t& width, uint32_t& height) const = 0; + [[nodiscard]] virtual int32_t get_latency() const { return 0.0f; } [[nodiscard]] virtual std::string load_name() const { return ""; } [[nodiscard]] virtual std::string load_vendor() const { return ""; } [[nodiscard]] virtual std::string get_parameter_name(int index) const = 0; + [[nodiscard]] virtual std::string get_parameter_label(int index) const { return ""; }; [[nodiscard]] virtual std::string get_parameter_display(int index) const { return ""; }; + [[nodiscard]] virtual int32_t get_param_count() const = 0; - [[nodiscard]] virtual bool is_param_index_valid(const int32_t index) const { return index >= 0 && index < get_param_count(); } + + [[nodiscard]] virtual bool is_param_index_valid(const int32_t index) const { + return index >= 0 && index < get_param_count(); + } + virtual void set_param_value(int32_t index, float value) = 0; + virtual float get_param_value(int32_t index) = 0; + virtual float get_param_min_value(int32_t index) { return 0.0f; } virtual float get_param_max_value(int32_t index) { return 1.0f; } @@ -81,16 +105,21 @@ public: [[nodiscard]] std::string get_imgui_id() const { return name + "##" + std::to_string(id); } + std::shared_ptr ui_buffers; multicast_delegate on_param_changed; // int32_t param_index, float value - multicast_delegate on_latency_changed; // int32_t latency_sample protected: void create_and_open_editor(); + void destroy_editor(); + virtual void on_open_editor(void* window_handle) = 0; + virtual void on_close_editor() = 0; + private: bool editor_opened = false; const uint64_t id = 0; - plugin_host_type type_; + plugin_host_type type_; + int32_t user_latency_ = 0; }; diff --git a/core/audio/plugin_host/plugin_host_manager.cpp b/core/audio/plugin_host/plugin_host_manager.cpp index 983c951..970d38a 100644 --- a/core/audio/plugin_host/plugin_host_manager.cpp +++ b/core/audio/plugin_host/plugin_host_manager.cpp @@ -24,14 +24,14 @@ void plugin_host_manager::release(singleton_release_guard& release_guard) { singleton_t::release(release_guard); release_guard.require_release(); - for (const plugin_host* host: plugin_hosts_) { - free_plugin_host(host); + for (plugin_host* host: plugin_hosts_) { + delete host; } plugin_hosts_.clear(); instrument_plugins_.clear(); } -plugin_host *plugin_host_manager::create_effect_plugin_host(const char *path) { +plugin_host* plugin_host_manager::create_effect_plugin_host(const char* path) { auto host = load_plugin(path); return host; } @@ -61,7 +61,7 @@ void plugin_host_manager::remove_instrument_plugin_host(plugin_host* host) { } plugin_host* plugin_host_manager::load_plugin(const char* path) { - auto host = alloc_plugin_host(); + auto host = new vst2_plugin_host(); try { host->load_plugin(path); } catch (std::exception& e) { diff --git a/core/audio/plugin_host/plugin_host_manager.h b/core/audio/plugin_host/plugin_host_manager.h index 33c9a69..96483f9 100644 --- a/core/audio/plugin_host/plugin_host_manager.h +++ b/core/audio/plugin_host/plugin_host_manager.h @@ -3,49 +3,48 @@ #include "misc/singleton/singleton.h" #include "taskflow/taskflow.hpp" #include "plugin_host.h" -#include "mempool.h" +#include "../../misc/mempool.h" #include class mixer_track; class CORE_API plugin_host_manager : public singleton_t { public: - void init(singleton_initliazer& initliazer) override; - void begin_release(singleton_release_guard& release_guard) override; - void release(singleton_release_guard& release_guard) override; + void init(singleton_initliazer& initliazer) override; - plugin_host* create_effect_plugin_host(const char* path); - plugin_host* create_instrument_plugin_host(const char* path); - void remove_instrument_plugin_host(plugin_host* host); + void begin_release(singleton_release_guard& release_guard) override; - const std::vector& get_plugin_hosts() { return plugin_hosts_; } - const std::vector& get_instrument_hosts() { return instrument_plugins_; } - void process(uint32_t in_frames); + void release(singleton_release_guard& release_guard) override; - const char* get_name() override { return "plugin_host_manager"; } + plugin_host* create_effect_plugin_host(const char* path); + + plugin_host* create_instrument_plugin_host(const char* path); + + void remove_instrument_plugin_host(plugin_host* host); + + const std::vector& get_plugin_hosts() { return plugin_hosts_; } + const std::vector& get_instrument_hosts() { return instrument_plugins_; } + + void process(uint32_t in_frames); + + const char* get_name() override { return "plugin_host_manager"; } + + multicast_delegate on_instrument_added; + multicast_delegate on_instrument_removed; - multicast_delegate on_instrument_added; - multicast_delegate on_instrument_removed; private: - plugin_host* load_plugin(const char* path); - void register_instrument_plugin(plugin_host* host); - void on_mixer_track_removed(mixer_track* track); + plugin_host* load_plugin(const char* path); - template - T* alloc_plugin_host() { - auto* host = plugin_host_map_[T::type].template alloc(); - return host; - } - template - void free_plugin_host(T* host) { - plugin_host_map_[host->get_type()].free(host); - } - std::vector instrument_plugins_{}; - std::vector plugin_hosts_{}; - std::unordered_map> plugin_host_map_; + void register_instrument_plugin(plugin_host* host); - void update_taskflow(uint32_t in_frames); - tf::Taskflow taskflow_; + void on_mixer_track_removed(mixer_track* track); + + std::vector instrument_plugins_{}; + std::vector plugin_hosts_{}; + + void update_taskflow(uint32_t in_frames); + + tf::Taskflow taskflow_; }; DEFINE_SINGLETON_INSTANCE(plugin_host_manager) diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp index 90b8c36..568d76e 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.cpp +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.cpp @@ -2,31 +2,19 @@ #include "audio/device/audio_device_manager.h" #include "audio/mixer/channel_interface.h" +#include "audio/mixer/latency_compensator.h" #include "window/window_manager.h" std::unordered_map> vst2_library_map; std::unordered_map vst2_latency_map; VstTimeInfo vst2_plugin_host::vst_time_info{}; -std::unordered_map can_do_map = -{ - {"sendVstEvents", true}, - {"sendVstMidiEvent", true}, - {"sendVstTimeInfo", true}, - {"receiveVstEvents", false}, - {"receiveVstMidiEvent", false}, - {"receiveVstTimeInfo", false}, - {"offline", false}, - {"reportConnectionChanges", false}, - {"acceptIOChanges", true}, - {"sizeWindow", true}, - {"asyncProcessing", true}, - {"supplyIdle", true}, - {"supportShell", false}, - {"openFileSelector", false}, - {"editFile", false}, - {"closeFileSelector", false}, - {"NIMKPIVendorSpecificCallbacks", false}, +std::unordered_map can_do_map = { + {"sendVstEvents", true}, {"sendVstMidiEvent", true}, {"sendVstTimeInfo", true}, {"receiveVstEvents", false}, + {"receiveVstMidiEvent", false}, {"receiveVstTimeInfo", false}, {"offline", false}, + {"reportConnectionChanges", false}, {"acceptIOChanges", true}, {"sizeWindow", true}, {"asyncProcessing", true}, + {"supplyIdle", true}, {"supportShell", false}, {"openFileSelector", false}, {"editFile", false}, + {"closeFileSelector", false}, {"NIMKPIVendorSpecificCallbacks", false}, }; std::shared_ptr get_vst2_library(const std::string& path) { @@ -38,109 +26,98 @@ std::shared_ptr get_vst2_library(const std::string& path) { return library; } -bool vst_host_can_do(const char* can_do) -{ - if (can_do_map.contains(can_do)) - return can_do_map[can_do]; +bool vst_host_can_do(const char* can_do) { + if (can_do_map.contains(can_do)) return can_do_map[can_do]; spdlog::warn("Unknown can do: {}", can_do); return false; } -VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) -{ - switch (opcode) - { - case audioMasterAutomate: { - auto host = ((vst2_plugin_host *) effect->user); +VstIntPtr vst_master_callback(AEffect* effect, VstInt32 opcode, VstInt32 index, VstIntPtr value, void* ptr, float opt) { + switch (opcode) { + case audioMasterAutomate : { + auto host = ((vst2_plugin_host*) effect->user); host->on_param_changed.broadcast(index, opt); -#if BUILD_DEBUG + #if BUILD_DEBUG spdlog::info("vst2 plugin {} automate, {} index = {}, value = {}", host->name, host->get_parameter_name(index), index, opt); -#endif + #endif auto old_latency = vst2_latency_map[host]; auto new_latency = host->get_latency(); if (old_latency != new_latency) { vst2_latency_map[host] = new_latency; - host->on_latency_changed.broadcast(new_latency); -#if BUILD_DEBUG + on_latency_offset_changed.broadcast(); + #if BUILD_DEBUG spdlog::info("vst2 plugin {} latency changed: {}", host->name, new_latency); -#endif + #endif } return 1; } - case audioMasterVersion: + case audioMasterVersion : return kVstVersion; // 返回插件版本号 - case audioMasterWantMidi: + case audioMasterWantMidi : return 1; - case audioMasterGetSampleRate: + case audioMasterGetSampleRate : return g_audio_device_manager.get_sample_rate(); // 返回采样率 - case audioMasterGetCurrentProcessLevel: + case audioMasterGetCurrentProcessLevel : return kVstProcessLevelRealtime; // 返回当前处理级别 - case audioMasterGetBlockSize: + case audioMasterGetBlockSize : return g_audio_device_manager.get_buffer_size(); // 返回块大小 - case audioMasterSizeWindow: - { + case audioMasterSizeWindow : { // 设置插件窗口大小 - g_window_manager.resize_plugin_window((plugin_host*)effect->user, index, value); + g_window_manager.resize_plugin_window((plugin_host*) effect->user, index, value); return 1; } - case audioMasterGetTime: - return (VstIntPtr)&vst2_time; - case audioMasterIdle: + case audioMasterGetTime : + return (VstIntPtr) &vst2_time; + case audioMasterIdle : // UE_LOG(LogTemp, Log, TEXT("Plugin Idle")); - return 1; - case audioMasterNeedIdle: + return 1; + case audioMasterNeedIdle : // UE_LOG(LogTemp, Log, TEXT("Plugin Need Idle")); - return 1; - case audioMasterGetVendorString: - { - const char* Ptr1 = (const char*)ptr; + return 1; + case audioMasterGetVendorString : { + const char* Ptr1 = (const char*) ptr; Ptr1 = "Arona"; return 1; } - case audioMasterGetProductString: - { - const char* Ptr1 = (const char*)ptr; + case audioMasterGetProductString : { + const char* Ptr1 = (const char*) ptr; Ptr1 = "Arona"; return 1; } - case audioMasterGetVendorVersion: + case audioMasterGetVendorVersion : return 1000; - case audioMasterCanDo: - { - const char* Ptr1 = (const char*)ptr; + case audioMasterCanDo : { + const char* Ptr1 = (const char*) ptr; return vst_host_can_do(Ptr1) ? 1 : 0; } - case audioMasterUpdateDisplay: + case audioMasterUpdateDisplay : return 1; - case audioMasterBeginEdit: - { + case audioMasterBeginEdit : { // UE_LOG(LogTemp, Log, TEXT("Want Begin Edit")); return 1; } - case audioMasterEndEdit: - { + case audioMasterEndEdit : { // UE_LOG(LogTemp, Log, TEXT("Want End Edit")); return 1; } - case audioMasterVendorSpecific: + case audioMasterVendorSpecific : return 0; - case audioMasterProcessEvents: + case audioMasterProcessEvents : // TODO { // VstEvents* Events = (VstEvents*)ptr; // Events->events[0]->type; // FVST2PluginHost* Host = static_cast(Effect->user); - } - case audioMasterGetInputLatency: + case audioMasterGetInputLatency : spdlog::info("Get Input Latency: {}", value); return 0; - case audioMasterGetOutputLatency: + case audioMasterGetOutputLatency : spdlog::info("Get Output Latency: {}", value); return 0; - return 1; - default: break; - // ensureMsgf(0, TEXT("No Implement OpCode: %d"), OpCode); + return 1; + default : break; + // ensureMsgf(0, TEXT("No Implement OpCode: %d"), OpCode); } return 1; @@ -165,7 +142,7 @@ bool vst2_plugin_host::load_plugin(const char* path) { // load vst library_ = get_vst2_library(path); // get main function - const auto entry_proc = (vst_plugin_entry_proc)(library_->get_function("VSTPluginMain")); + const auto entry_proc = (vst_plugin_entry_proc) (library_->get_function("VSTPluginMain")); if (!entry_proc) { spdlog::error("Failed to get entry point from {}", path); return false; @@ -175,8 +152,7 @@ bool vst2_plugin_host::load_plugin(const char* path) { if (!effect_) { return false; } - if (effect_->magic != kEffectMagic) - throw std::runtime_error("Not a VST2 plugin"); + if (effect_->magic != kEffectMagic) throw std::runtime_error("Not a VST2 plugin"); effect_->user = this; name = load_name(); @@ -213,20 +189,16 @@ uint32_t vst2_plugin_host::get_output_channels() const { } void vst2_plugin_host::update_channel_node_name() { - for (int i = 0; i < effect_->numInputs; ++i) - { + for (int i = 0; i < effect_->numInputs; ++i) { VstPinProperties pin_properties{}; - if (dispatch(effGetInputProperties, i, 0, &pin_properties) == 1) - { + if (dispatch(effGetInputProperties, i, 0, &pin_properties) == 1) { channel->set_input_channel_node_name(i / 2, i, pin_properties.label); } } - for (int i = 0; i < effect_->numOutputs; ++i) - { + for (int i = 0; i < effect_->numOutputs; ++i) { VstPinProperties pin_properties{}; - if (dispatch(effGetOutputProperties, i, 0, &pin_properties) == 1) - { + if (dispatch(effGetOutputProperties, i, 0, &pin_properties) == 1) { channel->set_output_channel_node_name(i / 2, i, pin_properties.label); } } @@ -234,14 +206,14 @@ void vst2_plugin_host::update_channel_node_name() { void vst2_plugin_host::process(uint32_t frame_num) { // TODO send midi -#if USE_DOUBLE_SAMPLE + #if USE_DOUBLE_SAMPLE effect_->processDoubleReplacing(effect_, channel->get_input_headers(), channel->get_output_headers(), static_cast(frame_num)); -#else - effect_->processReplacing(effect_, channel->get_input_headers(), channel->get_output_headers(), static_cast(frame_num)); -#endif + #else + effect_->processReplacing(effect_, channel->get_input_headers(), channel->get_output_headers(), + static_cast(frame_num)); + #endif - for (int i = 0; i < ui_buffers->size(); ++i) - { + for (int i = 0; i < ui_buffers->size(); ++i) { ui_buffers->at(i).push(channel->get_output_headers()[i], frame_num); } } @@ -283,14 +255,12 @@ std::string vst2_plugin_host::load_vendor() const { } void vst2_plugin_host::on_open_editor(void* window_handle) { - if (!has_editor()) - return; + if (!has_editor()) return; dispatch(effEditOpen, 0, 0, window_handle); } void vst2_plugin_host::on_close_editor() { - if (!has_editor()) - return; + if (!has_editor()) return; dispatch(effEditClose); } @@ -316,46 +286,34 @@ std::string vst2_plugin_host::get_parameter_display(int index) const { return buffer; } -int32_t vst2_plugin_host::get_param_count() const -{ - if (!effect_) - return 0; +int32_t vst2_plugin_host::get_param_count() const { + if (!effect_) return 0; return effect_->numParams; } -void vst2_plugin_host::set_param_value(int32_t index, float value) -{ - if (effect_) - effect_->setParameter(effect_, index, value); +void vst2_plugin_host::set_param_value(int32_t index, float value) { + if (effect_) effect_->setParameter(effect_, index, value); } -float vst2_plugin_host::get_param_value(int32_t index) -{ - if (!effect_) - return 0; +float vst2_plugin_host::get_param_value(int32_t index) { + if (!effect_) return 0; return effect_->getParameter(effect_, index); } float vst2_plugin_host::get_param_min_value(int32_t index) { VstParameterProperties param_properties{}; - if (dispatch(effGetParameterProperties, index, 0, ¶m_properties) == 1) - { - if (param_properties.flags & kVstParameterUsesIntegerMinMax) - return param_properties.minInteger; - if (param_properties.flags & kVstParameterUsesFloatStep) - return param_properties.smallStepFloat; + if (dispatch(effGetParameterProperties, index, 0, ¶m_properties) == 1) { + if (param_properties.flags & kVstParameterUsesIntegerMinMax) return param_properties.minInteger; + if (param_properties.flags & kVstParameterUsesFloatStep) return param_properties.smallStepFloat; } return plugin_host::get_param_min_value(index); } float vst2_plugin_host::get_param_max_value(int32_t index) { VstParameterProperties param_properties{}; - if (dispatch(effGetParameterProperties, index, 0, ¶m_properties) == 1) - { - if (param_properties.flags & kVstParameterUsesIntegerMinMax) - return param_properties.maxInteger; - if (param_properties.flags & kVstParameterUsesFloatStep) - return param_properties.largeStepFloat; + if (dispatch(effGetParameterProperties, index, 0, ¶m_properties) == 1) { + if (param_properties.flags & kVstParameterUsesIntegerMinMax) return param_properties.maxInteger; + if (param_properties.flags & kVstParameterUsesFloatStep) return param_properties.largeStepFloat; } return plugin_host::get_param_max_value(index); } diff --git a/core/audio/plugin_host/vst2/vst2_plugin_host.h b/core/audio/plugin_host/vst2/vst2_plugin_host.h index e6cdb01..e85f977 100644 --- a/core/audio/plugin_host/vst2/vst2_plugin_host.h +++ b/core/audio/plugin_host/vst2/vst2_plugin_host.h @@ -4,7 +4,7 @@ #include "pluginterfaces/vst2.x/aeffect.h" #include "pluginterfaces/vst2.x/aeffectx.h" -class vst2_plugin_host : public plugin_host { +class vst2_plugin_host : public plugin_host, public pool_obj { public: static VstTimeInfo vst_time_info; static constexpr auto type = plugin_host_type::vst2; diff --git a/core/misc/mempool.h b/core/misc/mempool.h new file mode 100644 index 0000000..5c72fe3 --- /dev/null +++ b/core/misc/mempool.h @@ -0,0 +1,121 @@ +#pragma once +#include +#include + +class memory_pool { +public: + memory_pool(const size_t chunk_size, const size_t chunks_per_block) + : chunk_size_(chunk_size), chunks_per_block_(chunks_per_block), current_block_(nullptr), free_list_(nullptr) { + allocate_block(); + } + memory_pool(memory_pool&& other) noexcept + : chunk_size_(other.chunk_size_), chunks_per_block_(other.chunks_per_block_), blocks_(std::move(other.blocks_)), + current_block_(other.current_block_), free_list_(other.free_list_) { + other.current_block_ = nullptr; + other.free_list_ = nullptr; + } + + ~memory_pool() { + for (void* block : blocks_) { + delete[] static_cast(block); + } + } + + auto allocate() -> void* { + if (!free_list_) { + allocate_block(); + } + + std::lock_guard lock(mutex_); + void* chunk = free_list_; + free_list_ = *static_cast(free_list_); + return chunk; + } + + void deallocate(void* chunk) { + std::lock_guard lock(mutex_); + *static_cast(chunk) = free_list_; + free_list_ = chunk; + } + +private: + void allocate_block() { + const size_t block_size = chunk_size_ * chunks_per_block_; + const auto new_block = new char[block_size]; + { + std::lock_guard lock(mutex_); + blocks_.push_back(new_block); + current_block_ = new_block; + } + + for (size_t i = 0; i < chunks_per_block_; ++i) { + void* chunk = new_block + i * chunk_size_; + deallocate(chunk); + } + } + + size_t chunk_size_; + size_t chunks_per_block_; + std::vector blocks_; + void* current_block_; + void* free_list_; + std::mutex mutex_; +}; + +template +class obj_mempool { +public: + template + static auto alloc(Args&&... args) -> T* { + auto obj = static_cast(pool_.allocate()); + new (obj) T(std::forward(args)...); + objs_.push_back(obj); + return obj; + } + static auto alloc() -> T* { + auto obj = static_cast(pool_.allocate()); + new (obj) T(); + objs_.push_back(obj); + return obj; + } + static void free(T* p) { + p->~T(); + pool_.deallocate(p); + objs_.erase(std::remove(objs_.begin(), objs_.end(), p), objs_.end()); + } + static void free_all() { + for (auto obj : objs_) { + obj->~T(); + pool_.deallocate(obj); + } + objs_.clear(); + } + static auto objs() -> const std::vector& { + return objs_; + } + static auto has_obj(T* p) -> bool { + return std::find(objs_.begin(), objs_.end(), p) != objs_.end(); + } + static auto safe_free(T* p) -> bool { + if (has_obj(p)) { + free(p); + return true; + } + return false; + } +private: + inline static memory_pool pool_ = memory_pool(sizeof(T), 64); + inline static std::vector objs_; +}; + +template +class pool_obj { + inline static memory_pool pool = memory_pool(sizeof(T), 64); +public: + auto operator new(size_t size) -> void* { + return pool.allocate(); + } + void operator delete(void* p) { + pool.deallocate(p); + } +}; diff --git a/core/thread_message/thread_message_hub.cpp b/core/thread_message/thread_message_hub.cpp index adecdc7..7efcef1 100644 --- a/core/thread_message/thread_message_hub.cpp +++ b/core/thread_message/thread_message_hub.cpp @@ -4,9 +4,9 @@ void thread_message_hub::process_messages() { while (!messages_.empty()) { - thread_message* message = messages_.front(); + lamba_thread_message* message = messages_.front(); message->execute(); - mem_pool_.free(message); + obj_mempool::free(message); messages_.pop(); } } diff --git a/core/thread_message/thread_message_hub.h b/core/thread_message/thread_message_hub.h index 2e47864..16df7d4 100644 --- a/core/thread_message/thread_message_hub.h +++ b/core/thread_message/thread_message_hub.h @@ -2,30 +2,29 @@ #include -#include "mempool.h" +#include "../misc/mempool.h" #include "thread_message.h" class CORE_API thread_message_hub { public: - template - void push_message(Args&&... args) { - T* message = mem_pool_.alloc(std::forward(args)...); - push_message(message); - } - template - void push_message() { - T* message = mem_pool_.alloc(); - push_message(message); - } + // template + // void push_message(Args&&... args) { + // T* message = obj_mempool::alloc(std::forward(args)...); + // push_message(message); + // } + // template + // void push_message() { + // T* message = obj_mempool::alloc(); + // push_message(message); + // } void push_message(const std::function& func) { - auto* message = mem_pool_.alloc(func); + auto* message = obj_mempool::alloc(func); push_message(message); } void process_messages(); private: - void push_message(thread_message* message) { + void push_message(lamba_thread_message* message) { messages_.push(message); } - std::queue messages_; - mempool<> mem_pool_ = mempool(1024000); + std::queue messages_; }; diff --git a/third_party/mempool/CMakeLists.txt b/third_party/mempool/CMakeLists.txt index cf570b6..c0f556f 100644 --- a/third_party/mempool/CMakeLists.txt +++ b/third_party/mempool/CMakeLists.txt @@ -5,12 +5,7 @@ set(CMAKE_C_STANDARD 99) set(CMAKE_CPP_STANDARD 17) add_library(${PROJECT_NAME} SHARED - mempool/ncx_core.h - mempool/ncx_lock.h - mempool/ncx_slab.c - mempool/ncx_slab.h - mempool/my_unistd.h - mempool.h + ../../core/misc/mempool.h extern.h ) include_directories(mempool) diff --git a/third_party/mempool/mempool.h b/third_party/mempool/mempool.h deleted file mode 100644 index a897b17..0000000 --- a/third_party/mempool/mempool.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once -#include "ncx_slab.h" -#include - -template -class mempool { -public: - mempool(size_t pool_size = 1024000) { // 1024KB - const auto space = static_cast(malloc(pool_size)); - - mem_pool_ = reinterpret_cast(space); - mem_pool_->addr = space; - mem_pool_->min_shift = 3; - mem_pool_->end = space + pool_size; - - ncx_slab_init(mem_pool_); - } - ~mempool() { - free(mem_pool_->addr); - } - [[nodiscard]] void* alloc(size_t size) const { - return ncx_slab_alloc(mem_pool_, size); - } - - template - [[nodiscard]] T* alloc(Args&&... args) const { - T* out = (T*)alloc(sizeof(T)); - new (out) T(std::forward(args)...); - return out; - } - template - [[nodiscard]] T* alloc() const { - T* out = (T*)alloc(sizeof(T)); - new (out) T(); - return out; - } - - template - void free(T* p) const { - p->~T(); - free((void*)p); - } - - void free(void* p) const { - ncx_slab_free(mem_pool_, p); - } - [[nodiscard]] ncx_slab_stat_t stat() const { - ncx_slab_stat_t out; - ncx_slab_stat(mem_pool_, &out); - return out; - } -private: - ncx_slab_pool_t* mem_pool_ = nullptr; -}; - -template -class obj_mempool { -public: - template - static T* alloc(Args&&... args) { - auto obj = pool_.template alloc(std::forward(args)...); - objs_.push_back(obj); - return obj; - } - static T* alloc() { - auto obj = pool_.template alloc(); - objs_.push_back(obj); - return obj; - } - static void free(T* p) { - pool_.template free(p); - objs_.erase(std::remove(objs_.begin(), objs_.end(), p), objs_.end()); - } - static void free_all() { - for (auto obj : objs_) { - pool_.template free(obj); - } - objs_.clear(); - } - static const std::vector& objs() { - return objs_; - } - static bool has_obj(T* p) { - return std::find(objs_.begin(), objs_.end(), p) != objs_.end(); - } - static bool safe_free(T* p) { - if (has_obj(p)) { - free(p); - return true; - } - return false; - } -private: - static mempool pool_; - static std::vector objs_; -}; diff --git a/third_party/mempool/mempool/Makefile b/third_party/mempool/mempool/Makefile deleted file mode 100644 index b9f32f0..0000000 --- a/third_party/mempool/mempool/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -CC=gcc -CXX=g++ -INC+= -LIB+= - -#判断系统架构(32bit, 64bit) -ARCH := $(shell getconf LONG_BIT) -ifeq ($(ARCH),64) -CFLAGS+= -DNCX_PTR_SIZE=8 -else -CFLAGS+= -DNCX_PTR_SIZE=4 -endif - -#CFLAGS+= -pipe -O0 -Wall -g3 -ggdb3 -CFLAGS+= -pipe -O3 -#定义是否打印日志 -CFLAGS+= -DLOG_LEVEL=4 -#是否与malloc类似模拟脏数据 -#CFLAGS+= -DNCX_DEBUG_MALLOC -#是否自动合并碎片 -CFLAGS+= -DPAGE_MERGE - -TARGET=pool_test -ALL:$(TARGET) - -OBJ= ncx_slab.o - -$(TARGET):$(OBJ) main.o - $(CC) $(CFLAGS) -o $@ $^ $(LIB) - -pool_bench:$(OBJ) bench.o - $(CC) $(CFLAGS) -o $@ $^ $(LIB) - -%.o: %.c - $(CC) $(CFLAGS) $(INC) -c -o $@ $< - -clean: - rm -f *.o - rm -f $(TARGET) pool_bench - -install: diff --git a/third_party/mempool/mempool/README.md b/third_party/mempool/mempool/README.md deleted file mode 100644 index aa6d977..0000000 --- a/third_party/mempool/mempool/README.md +++ /dev/null @@ -1,106 +0,0 @@ -ncx_mempool -====================== - -Description -=========== - -a nginx-based memory pool .
-both share-memory and private-memory are supported. it is more efficient than malloc.
-it is a very light weight and do not rely on any third-party library. - -Examples -======== - - 1 #include "ncx_slab.h" - 2 - 3 int main(int argc, char **argv) - 4 { - 5 char *p; - 6 size_t pool_size = 4096000; //4M - 7 ncx_slab_stat_t stat; - 8 u_char *space; - 9 space = (u_char *)malloc(pool_size); - 10 - 11 ncx_slab_pool_t *sp; - 12 sp = (ncx_slab_pool_t*) space; - 13 - 14 sp->addr = space; - 15 sp->min_shift = 3; - 16 sp->end = space + pool_size; - 17 - 18 /* - 19 * init - 20 */ - 21 ncx_slab_init(sp); - 22 - 23 /* - 24 * alloc - 25 */ - 26 p = ncx_slab_alloc(sp, 128); - 27 - 28 /* - 29 * memory usage api. - 30 */ - 31 ncx_slab_stat(sp, &stat); - 32 - 33 /* - 34 * free - 35 */ - 36 ncx_slab_free(sp, p); - 37 - 38 free(space); - 39 - 40 return 0; - 41} - -API -=== -**ncx_slab_init(ncx_slab_pool_t *pool)**
-**Description**: 初始化内存池结构; - -**ncx_slab_alloc(ncx_slab_pool_t *pool, size_t size)**
-**Description**: 内存分配 - -**ncx_slab_free(ncx_slab_pool_t *pool, void *p)**
-**Description**: 释放内存 - -**ncx_slab_stat(ncx_slab_pool_t *pool, ncx_slab_stat_t *stat)**
-**Description**: 查看内存池使用情况 - -Customization -============= -正如example所示,内存池内存是由应用层先分配,ncx_mempool是在给定的内存基础上进行分配和回收管理。
-所以内存池本身不关心所管理的内存是私有内存 or 共享内存; - -ncx_lock.h 是锁接口;根据实际需要重定义:
-1.多线程共享内存池,可参考pthread_spin_lock
-2.多进程共享内存池,可参考nginx的ngx_shmtx.c实现spin lock
-3.单进程单线程使用内存池,无锁编程.. - -ncx_log.h 是日志接口,根据实际需要重定义. - -ncx_slab.c.orz 是 ncx_slab.c的详细注释,方便理解. - -Author -====== -dcshi(施俊伟) - -Copyright and License -===================== -This module is licensed under the BSD license. -Copyright (C) 2013, by dcshi(施俊伟). -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and - the following disclaimer in the documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, -OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/mempool/mempool/bench.c b/third_party/mempool/mempool/bench.c deleted file mode 100644 index 791cca4..0000000 --- a/third_party/mempool/mempool/bench.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "ncx_slab.h" -#include - -uint64_t usTime() -{ - struct timeval tv; - uint64_t usec; - - gettimeofday(&tv, NULL); - - usec = ((uint64_t)tv.tv_sec)*1000000LL; - usec += tv.tv_usec; - - return usec; -} - -int main(int argc, char **argv) -{ - ncx_slab_pool_t *sp; - size_t pool_size; - u_char *space; - - pool_size = 4096000; //4M - space = (u_char *)malloc(pool_size); - sp = (ncx_slab_pool_t*) space; - - sp->addr = space; - sp->min_shift = 3; - sp->end = space + pool_size; - - ncx_slab_init(sp); - - char *p; - uint64_t us_begin; - uint64_t us_end; - size_t size[] = { 30, 120, 256, 500, 1000, 2000, 3000, 5000}; - - printf("size\tncx\tmalloc\tpct\n"); - - int i, j; - uint64_t t1, t2; - for (j = 0; j < sizeof(size)/sizeof(size_t); j++) - { - size_t s = size[j]; - printf("%d\t", s); - - //test for ncx_pool - us_begin = usTime(); - for(i = 0; i < 1000000; i++) - { - p = ncx_slab_alloc(sp, s); - - ncx_slab_free(sp, p); - } - us_end = usTime(); - - t1 = (us_end - us_begin); - printf("%llu \t", t1/1000); - - // test for malloc - us_begin = usTime(); - for(i = 0; i < 1000000; i++) - { - p = (char*)malloc(s); - - free(p); - } - us_end = usTime(); - - t2 = (us_end - us_begin); - printf("%llu\t", t2/1000); - - printf("%.2f\n", (double)t1 / (double)t2); - } - - free(space); - - return 0; -} diff --git a/third_party/mempool/mempool/main.c b/third_party/mempool/mempool/main.c deleted file mode 100644 index f021144..0000000 --- a/third_party/mempool/mempool/main.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "ncx_slab.h" - -int main(int argc, char **argv) -{ - char *p; - size_t pool_size = 4096000; //4M - ncx_slab_stat_t stat; - u_char *space; - space = (u_char *)malloc(pool_size); - - ncx_slab_pool_t *sp; - sp = (ncx_slab_pool_t*) space; - - sp->addr = space; - sp->min_shift = 3; - sp->end = space + pool_size; - - ncx_slab_init(sp); - - int i; - for (i = 0; i < 1000000; i++) - { - p = ncx_slab_alloc(sp, 128 + i); - if (p == NULL) - { - printf("%d\n", i); - return -1; - } - ncx_slab_free(sp, p); - } - ncx_slab_stat(sp, &stat); - - printf("##########################################################################\n"); - for (i = 0; i < 2500; i++) - { - p = ncx_slab_alloc(sp, 30 + i); - if (p == NULL) - { - printf("%d\n", i); - return -1; - } - - if (i % 3 == 0) - { - ncx_slab_free(sp, p); - } - } - ncx_slab_stat(sp, &stat); - - free(space); - - return 0; -} diff --git a/third_party/mempool/mempool/my_unistd.h b/third_party/mempool/mempool/my_unistd.h deleted file mode 100644 index 1cbfd7c..0000000 --- a/third_party/mempool/mempool/my_unistd.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#ifdef WIN32 -#include -inline uintptr_t getpagesize() { - SYSTEM_INFO systemInfo; - GetSystemInfo(&systemInfo); - return systemInfo.dwPageSize; -} -#else -#include -#endif \ No newline at end of file diff --git a/third_party/mempool/mempool/ncx_core.h b/third_party/mempool/mempool/ncx_core.h deleted file mode 100644 index a2a200b..0000000 --- a/third_party/mempool/mempool/ncx_core.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _NCX_CORE_H_ -#define _NCX_CORE_H_ - -#include -#include -#include -#include -#include - -typedef unsigned char u_char; -typedef uintptr_t ncx_uint_t; -typedef intptr_t ncx_int_t; - -#ifndef NCX_ALIGNMENT -#define NCX_ALIGNMENT sizeof(unsigned long) /* platform word */ -#endif - -#define ncx_align(d, a) (((d) + (a - 1)) & ~(a - 1)) -#define ncx_align_ptr(p, a) \ - (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) - -#define ncx_memzero(buf, n) (void) memset(buf, 0, n) -#define ncx_memset(buf, c, n) (void) memset(buf, c, n) - -#endif diff --git a/third_party/mempool/mempool/ncx_lock.h b/third_party/mempool/mempool/ncx_lock.h deleted file mode 100644 index a1161cc..0000000 --- a/third_party/mempool/mempool/ncx_lock.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _NCX_LOCK_H_ -#define _NCX_LOCK_H_ - -#define ncx_shmtx_lock(x) { /*void*/ } -#define ncx_shmtx_unlock(x) { /*void*/ } - -typedef struct { - - ncx_uint_t spin; - -} ncx_shmtx_t; - -#endif diff --git a/third_party/mempool/mempool/ncx_slab.c b/third_party/mempool/mempool/ncx_slab.c deleted file mode 100644 index aabb711..0000000 --- a/third_party/mempool/mempool/ncx_slab.c +++ /dev/null @@ -1,848 +0,0 @@ -#include "ncx_slab.h" -#include - -#define NCX_SLAB_PAGE_MASK 3 -#define NCX_SLAB_PAGE 0 -#define NCX_SLAB_BIG 1 -#define NCX_SLAB_EXACT 2 -#define NCX_SLAB_SMALL 3 - -#if (NCX_PTR_SIZE == 4) - -#define NCX_SLAB_PAGE_FREE 0 -#define NCX_SLAB_PAGE_BUSY 0xffffffff -#define NCX_SLAB_PAGE_START 0x80000000 - -#define NCX_SLAB_SHIFT_MASK 0x0000000f -#define NCX_SLAB_MAP_MASK 0xffff0000 -#define NCX_SLAB_MAP_SHIFT 16 - -#define NCX_SLAB_BUSY 0xffffffff - -#else /* (NCX_PTR_SIZE == 8) */ - -#define NCX_SLAB_PAGE_FREE 0 -#define NCX_SLAB_PAGE_BUSY 0xffffffffffffffff -#define NCX_SLAB_PAGE_START 0x8000000000000000 - -#define NCX_SLAB_SHIFT_MASK 0x000000000000000f -#define NCX_SLAB_MAP_MASK 0xffffffff00000000 -#define NCX_SLAB_MAP_SHIFT 32 - -#define NCX_SLAB_BUSY 0xffffffffffffffff - -#endif - - -#if (NCX_DEBUG_MALLOC) - -#define ncx_slab_junk(p, size) ncx_memset(p, 0xA5, size) - -#else - -#define ncx_slab_junk(p, size) - -#endif - - -static ncx_slab_page_t* ncx_slab_alloc_pages(ncx_slab_pool_t* pool, - ncx_uint_t pages); - -static void ncx_slab_free_pages(ncx_slab_pool_t* pool, ncx_slab_page_t* page, - ncx_uint_t pages); - -static bool ncx_slab_empty(ncx_slab_pool_t* pool, ncx_slab_page_t* page); - -static ncx_uint_t ncx_slab_max_size; -static ncx_uint_t ncx_slab_exact_size; -static ncx_uint_t ncx_slab_exact_shift; -static ncx_uint_t ncx_pagesize; -static ncx_uint_t ncx_pagesize_shift; -static ncx_uint_t ncx_real_pages; - -#ifdef __APPLE__ -#include -#include -#endif - -void ncx_slab_init(ncx_slab_pool_t* pool) { - u_char* p; - size_t size; - ncx_uint_t i, n, pages; - ncx_slab_page_t* slots; - - /*pagesize*/ -#ifdef __APPLE__ - vm_size_t pagesize; - host_page_size(mach_host_self(), &pagesize); - ncx_pagesize = pagesize; -#else - ncx_pagesize = getpagesize(); -#endif - for (n = ncx_pagesize, ncx_pagesize_shift = 0; - n >>= 1; ncx_pagesize_shift++) { - /* void */ - } - - /* STUB */ - if (ncx_slab_max_size == 0) { - ncx_slab_max_size = ncx_pagesize / 2; - ncx_slab_exact_size = ncx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ncx_slab_exact_size; n >>= 1; ncx_slab_exact_shift++) { - /* void */ - } - } - - pool->min_size = 1 << pool->min_shift; - - p = (u_char*) pool + sizeof(ncx_slab_pool_t); - slots = (ncx_slab_page_t*) p; - - n = ncx_pagesize_shift - pool->min_shift; - for (i = 0; i < n; i++) { - slots[i].slab = 0; - slots[i].next = &slots[i]; - slots[i].prev = 0; - } - - p += n * sizeof(ncx_slab_page_t); - - size = pool->end - p; - ncx_slab_junk(p, size); - - pages = (ncx_uint_t) (size / (ncx_pagesize + sizeof(ncx_slab_page_t))); - - ncx_memzero(p, pages * sizeof(ncx_slab_page_t)); - - pool->pages = (ncx_slab_page_t*) p; - - pool->free.prev = 0; - pool->free.next = (ncx_slab_page_t*) p; - - pool->pages->slab = pages; - pool->pages->next = &pool->free; - pool->pages->prev = (uintptr_t) &pool->free; - - pool->start = (u_char*) - ncx_align_ptr((uintptr_t) p + pages * sizeof(ncx_slab_page_t), - ncx_pagesize); - - ncx_real_pages = (pool->end - pool->start) / ncx_pagesize; - pool->pages->slab = ncx_real_pages; -} - - -void* ncx_slab_alloc(ncx_slab_pool_t* pool, size_t size) { - ncx_shmtx_lock(&pool->mutex); - - void* p = ncx_slab_alloc_locked(pool, size); - - ncx_shmtx_unlock(&pool->mutex); - - return p; -} - - -void* ncx_slab_alloc_locked(ncx_slab_pool_t* pool, size_t size) { - size_t s; - uintptr_t p, n, m, mask,* bitmap; - ncx_uint_t i, slot, shift, map; - ncx_slab_page_t* page,* prev,* slots; - - if (size >= ncx_slab_max_size) { - // debug("slab alloc: %zu", size); - - page = ncx_slab_alloc_pages(pool, (size >> ncx_pagesize_shift) - + ((size % ncx_pagesize) ? 1 : 0)); - if (page) { - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - } else { - p = 0; - } - - goto done; - } - - if (size > pool->min_size) { - shift = 1; - for (s = size - 1; s >>= 1; shift++) { - /* void */ - } - slot = shift - pool->min_shift; - } else { - size = pool->min_size; - shift = pool->min_shift; - slot = 0; - } - - slots = (ncx_slab_page_t*) ((u_char*) pool + sizeof(ncx_slab_pool_t)); - page = slots[slot].next; - - if (page->next != page) { - if (shift < ncx_slab_exact_shift) { - do { - p = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t*) (pool->start + p); - - map = (1 << (ncx_pagesize_shift - shift)) - / (sizeof(uintptr_t) * 8); - - for (n = 0; n < map; n++) { - if (bitmap[n] != NCX_SLAB_BUSY) { - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((bitmap[n] & m)) { - continue; - } - - bitmap[n] |= m; - - i = ((n * sizeof(uintptr_t) * 8) << shift) - + (i << shift); - - if (bitmap[n] == NCX_SLAB_BUSY) { - for (n = n + 1; n < map; n++) { - if (bitmap[n] != NCX_SLAB_BUSY) { - p = (uintptr_t) bitmap + i; - - goto done; - } - } - - prev = (ncx_slab_page_t*) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NCX_SLAB_SMALL; - } - - p = (uintptr_t) bitmap + i; - - goto done; - } - } - } - - page = page->next; - } while (page); - } else if (shift == ncx_slab_exact_shift) { - do { - if (page->slab != NCX_SLAB_BUSY) { - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if (page->slab == NCX_SLAB_BUSY) { - prev = (ncx_slab_page_t*) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NCX_SLAB_EXACT; - } - - p = (page - pool->pages) << ncx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - page = page->next; - } while (page); - } else { - /* shift > ncx_slab_exact_shift */ - - n = ncx_pagesize_shift - (page->slab & NCX_SLAB_SHIFT_MASK); - n = 1 << n; - n = ((uintptr_t) 1 << n) - 1; - mask = n << NCX_SLAB_MAP_SHIFT; - - do { - if ((page->slab & NCX_SLAB_MAP_MASK) != mask) { - for (m = (uintptr_t) 1 << NCX_SLAB_MAP_SHIFT, i = 0; - m & mask; - m <<= 1, i++) { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if ((page->slab & NCX_SLAB_MAP_MASK) == mask) { - prev = (ncx_slab_page_t*) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NCX_SLAB_BIG; - } - - p = (page - pool->pages) << ncx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - page = page->next; - } while (page); - } - } - - page = ncx_slab_alloc_pages(pool, 1); - - if (page) { - if (shift < ncx_slab_exact_shift) { - p = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t*) (pool->start + p); - - s = 1 << shift; - n = (1 << (ncx_pagesize_shift - shift)) / 8 / s; - - if (n == 0) { - n = 1; - } - - bitmap[0] = (2 << n) - 1; - - map = (1 << (ncx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); - - for (i = 1; i < map; i++) { - bitmap[i] = 0; - } - - page->slab = shift; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_SMALL; - - slots[slot].next = page; - - p = ((page - pool->pages) << ncx_pagesize_shift) + s * n; - p += (uintptr_t) pool->start; - - goto done; - } else if (shift == ncx_slab_exact_shift) { - page->slab = 1; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_EXACT; - - slots[slot].next = page; - - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - - goto done; - } else { - /* shift > ncx_slab_exact_shift */ - - page->slab = ((uintptr_t) 1 << NCX_SLAB_MAP_SHIFT) | shift; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_BIG; - - slots[slot].next = page; - - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - p = 0; - -done: - - // debug("slab alloc: %p", (void *)p); - - return (void*) p; -} - - -void ncx_slab_free(ncx_slab_pool_t* pool, void* p) { - ncx_shmtx_lock(&pool->mutex); - - ncx_slab_free_locked(pool, p); - - ncx_shmtx_unlock(&pool->mutex); -} - - -void ncx_slab_free_locked(ncx_slab_pool_t* pool, void* p) { - size_t size; - uintptr_t slab, m,* bitmap; - ncx_uint_t n, type, slot, shift, map; - ncx_slab_page_t* slots,* page; - - // debug("slab free: %p", p); - - if ((u_char*) p < pool->start || (u_char*) p > pool->end) { - // error("ncx_slab_free(): outside of pool"); - goto fail; - } - - n = ((u_char*) p - pool->start) >> ncx_pagesize_shift; - page = &pool->pages[n]; - slab = page->slab; - type = page->prev & NCX_SLAB_PAGE_MASK; - - switch (type) { - case NCX_SLAB_SMALL: - - shift = slab & NCX_SLAB_SHIFT_MASK; - size = 1 << shift; - - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - n = ((uintptr_t) p & (ncx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); - n /= (sizeof(uintptr_t) * 8); - bitmap = (uintptr_t*) ((uintptr_t) p & ~(ncx_pagesize - 1)); - - if (bitmap[n] & m) { - if (page->next == NULL) { - slots = (ncx_slab_page_t*) - ((u_char*) pool + sizeof(ncx_slab_pool_t)); - slot = shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_SMALL; - page->next->prev = (uintptr_t) page | NCX_SLAB_SMALL; - } - - bitmap[n] &= ~m; - - n = (1 << (ncx_pagesize_shift - shift)) / 8 / (1 << shift); - - if (n == 0) { - n = 1; - } - - if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { - goto done; - } - - map = (1 << (ncx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); - - for (n = 1; n < map; n++) { - if (bitmap[n]) { - goto done; - } - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_EXACT: - - m = (uintptr_t) 1 << - (((uintptr_t) p & (ncx_pagesize - 1)) >> ncx_slab_exact_shift); - size = ncx_slab_exact_size; - - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - if (slab & m) { - if (slab == NCX_SLAB_BUSY) { - slots = (ncx_slab_page_t*) - ((u_char*) pool + sizeof(ncx_slab_pool_t)); - slot = ncx_slab_exact_shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_EXACT; - page->next->prev = (uintptr_t) page | NCX_SLAB_EXACT; - } - - page->slab &= ~m; - - if (page->slab) { - goto done; - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_BIG: - - shift = slab & NCX_SLAB_SHIFT_MASK; - size = 1 << shift; - - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - m = (uintptr_t) 1 << ((((uintptr_t) p & (ncx_pagesize - 1)) >> shift) - + NCX_SLAB_MAP_SHIFT); - - if (slab & m) { - if (page->next == NULL) { - slots = (ncx_slab_page_t*) - ((u_char*) pool + sizeof(ncx_slab_pool_t)); - slot = shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_BIG; - page->next->prev = (uintptr_t) page | NCX_SLAB_BIG; - } - - page->slab &= ~m; - - if (page->slab & NCX_SLAB_MAP_MASK) { - goto done; - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_PAGE: - - if ((uintptr_t) p & (ncx_pagesize - 1)) { - goto wrong_chunk; - } - - if (slab == NCX_SLAB_PAGE_FREE) { - // alert("ncx_slab_free(): page is already free"); - goto fail; - } - - if (slab == NCX_SLAB_PAGE_BUSY) { - // alert("ncx_slab_free(): pointer to wrong page"); - goto fail; - } - - n = ((u_char*) p - pool->start) >> ncx_pagesize_shift; - size = slab & ~NCX_SLAB_PAGE_START; - - ncx_slab_free_pages(pool, &pool->pages[n], size); - - ncx_slab_junk(p, size << ncx_pagesize_shift); - - return; - } - - /* not reached */ - - return; - -done: - - ncx_slab_junk(p, size); - - return; - -wrong_chunk: - - // error("ncx_slab_free(): pointer to wrong chunk"); - - goto fail; - -chunk_already_free: - - // error("ncx_slab_free(): chunk is already free"); - -fail: - - return; -} - - -static ncx_slab_page_t* ncx_slab_alloc_pages(ncx_slab_pool_t* pool, ncx_uint_t pages) { - ncx_slab_page_t* page,* p; - - for (page = pool->free.next; page != &pool->free; page = page->next) { - if (page->slab >= pages) { - if (page->slab > pages) { - page[pages].slab = page->slab - pages; - page[pages].next = page->next; - page[pages].prev = page->prev; - - p = (ncx_slab_page_t*) page->prev; - p->next = &page[pages]; - page->next->prev = (uintptr_t) &page[pages]; - } else { - p = (ncx_slab_page_t*) page->prev; - p->next = page->next; - page->next->prev = page->prev; - } - - page->slab = pages | NCX_SLAB_PAGE_START; - page->next = NULL; - page->prev = NCX_SLAB_PAGE; - - if (--pages == 0) { - return page; - } - - for (p = page + 1; pages; pages--) { - p->slab = NCX_SLAB_PAGE_BUSY; - p->next = NULL; - p->prev = NCX_SLAB_PAGE; - p++; - } - - return page; - } - } - - // error("ncx_slab_alloc() failed: no memory"); - - return NULL; -} - -static void ncx_slab_free_pages(ncx_slab_pool_t* pool, ncx_slab_page_t* page, - ncx_uint_t pages) { - ncx_slab_page_t* prev,* next; - - if (pages > 1) { - ncx_memzero(&page[1], (pages - 1)* sizeof(ncx_slab_page_t)); - } - - if (page->next) { - prev = (ncx_slab_page_t*) (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - } - - page->slab = pages; - page->prev = (uintptr_t) &pool->free; - page->next = pool->free.next; - page->next->prev = (uintptr_t) page; - - pool->free.next = page; - -#ifdef PAGE_MERGE - if (pool->pages != page) { - prev = page - 1; - if (ncx_slab_empty(pool, prev)) { - for (; prev >= pool->pages; prev--) { - if (prev->slab != 0) - { - pool->free.next = page->next; - page->next->prev = (uintptr_t) &pool->free; - - prev->slab += pages; - ncx_memzero(page, sizeof(ncx_slab_page_t)); - - page = prev; - - break; - } - } - } - } - - if ((page - pool->pages + page->slab) < ncx_real_pages) { - next = page + page->slab; - if (ncx_slab_empty(pool, next)) - { - prev = (ncx_slab_page_t *) (next->prev); - prev->next = next->next; - next->next->prev = next->prev; - - page->slab += next->slab; - ncx_memzero(next, sizeof(ncx_slab_page_t)); - } - } - -#endif -} - -void ncx_slab_dummy_init(ncx_slab_pool_t* pool) { - ncx_uint_t n; - -#ifdef __APPLE__ - vm_size_t pagesize; - host_page_size(mach_host_self(), &pagesize); - ncx_pagesize = pagesize; -#else - ncx_pagesize = getpagesize(); -#endif - for (n = ncx_pagesize, ncx_pagesize_shift = 0; - n >>= 1; ncx_pagesize_shift++) { - /* void */ - } - - if (ncx_slab_max_size == 0) { - ncx_slab_max_size = ncx_pagesize / 2; - ncx_slab_exact_size = ncx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ncx_slab_exact_size; n >>= 1; ncx_slab_exact_shift++) { - /* void */ - } - } -} - -void ncx_slab_stat(ncx_slab_pool_t* pool, ncx_slab_stat_t* stat) { - uintptr_t m, n, mask, slab; - uintptr_t* bitmap; - ncx_uint_t i, j, map, type, obj_size; - ncx_slab_page_t* page; - - ncx_memzero(stat, sizeof(ncx_slab_stat_t)); - - page = pool->pages; - stat->pages = (pool->end - pool->start) / ncx_pagesize;; - - for (i = 0; i < stat->pages; i++) { - slab = page->slab; - type = page->prev & NCX_SLAB_PAGE_MASK; - - switch (type) { - case NCX_SLAB_SMALL: - - n = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t*) (pool->start + n); - - obj_size = 1 << slab; - map = (1 << (ncx_pagesize_shift - slab)) - / (sizeof(uintptr_t) * 8); - - for (j = 0; j < map; j++) { - for (m = 1; m; m <<= 1) { - if ((bitmap[j] & m)) { - stat->used_size += obj_size; - stat->b_small += obj_size; - } - } - } - - stat->p_small++; - - break; - - case NCX_SLAB_EXACT: - - if (slab == NCX_SLAB_BUSY) { - stat->used_size += sizeof(uintptr_t) * 8 * ncx_slab_exact_size; - stat->b_exact += sizeof(uintptr_t) * 8 * ncx_slab_exact_size; - } else { - for (m = 1; m; m <<= 1) { - if (slab & m) { - stat->used_size += ncx_slab_exact_size; - stat->b_exact += ncx_slab_exact_size; - } - } - } - - stat->p_exact++; - - break; - - case NCX_SLAB_BIG: - - j = ncx_pagesize_shift - (slab & NCX_SLAB_SHIFT_MASK); - j = 1 << j; - j = ((uintptr_t) 1 << j) - 1; - mask = j << NCX_SLAB_MAP_SHIFT; - obj_size = 1 << (slab & NCX_SLAB_SHIFT_MASK); - - for (m = (uintptr_t) 1 << NCX_SLAB_MAP_SHIFT; m & mask; m <<= 1) { - if ((page->slab & m)) { - stat->used_size += obj_size; - stat->b_big += obj_size; - } - } - - stat->p_big++; - - break; - - case NCX_SLAB_PAGE: - - if (page->prev == NCX_SLAB_PAGE) { - slab = slab & ~NCX_SLAB_PAGE_START; - stat->used_size += slab * ncx_pagesize; - stat->b_page += slab * ncx_pagesize; - stat->p_page += slab; - - i += (slab - 1); - - break; - } - - default: - - if (slab > stat->max_free_pages) { - stat->max_free_pages = page->slab; - } - - stat->free_page += slab; - - i += (slab - 1); - - break; - } - - page = pool->pages + i + 1; - } - - stat->pool_size = pool->end - pool->start; - stat->used_pct = stat->used_size * 100 / stat->pool_size; - - // info("pool_size : %zu bytes", stat->pool_size); - // info("used_size : %zu bytes", stat->used_size); - // info("used_pct : %zu%%\n", stat->used_pct); - - // info("total page count : %zu", stat->pages); - // info("free page count : %zu\n", stat->free_page); - - // info("small slab use page : %zu,\tbytes : %zu", stat->p_small, stat->b_small); - // info("exact slab use page : %zu,\tbytes : %zu", stat->p_exact, stat->b_exact); - // info("big slab use page : %zu,\tbytes : %zu", stat->p_big, stat->b_big); - // info("page slab use page : %zu,\tbytes : %zu\n", stat->p_page, stat->b_page); - - // info("max free pages : %zu\n", stat->max_free_pages); -} - -static bool ncx_slab_empty(ncx_slab_pool_t* pool, ncx_slab_page_t* page) { - ncx_slab_page_t* prev; - - if (page->slab == 0) { - return true; - } - - //page->prev == PAGE | SMALL | EXACT | BIG - if (page->next == NULL) { - return false; - } - - prev = (ncx_slab_page_t*) (page->prev & ~NCX_SLAB_PAGE_MASK); - while (prev >= pool->pages) { - prev = (ncx_slab_page_t*) (prev->prev & ~NCX_SLAB_PAGE_MASK); - }; - - if (prev == &pool->free) { - return true; - } - - return false; -} diff --git a/third_party/mempool/mempool/ncx_slab.c.orz b/third_party/mempool/mempool/ncx_slab.c.orz deleted file mode 100644 index d59958e..0000000 --- a/third_party/mempool/mempool/ncx_slab.c.orz +++ /dev/null @@ -1,1133 +0,0 @@ -#include "ncx_slab.h" -#include - -#define NCX_SLAB_PAGE_MASK 3 -#define NCX_SLAB_PAGE 0 -#define NCX_SLAB_BIG 1 -#define NCX_SLAB_EXACT 2 -#define NCX_SLAB_SMALL 3 - -#if (NCX_PTR_SIZE == 4) - -#define NCX_SLAB_PAGE_FREE 0 -#define NCX_SLAB_PAGE_BUSY 0xffffffff -#define NCX_SLAB_PAGE_START 0x80000000 - -#define NCX_SLAB_SHIFT_MASK 0x0000000f -#define NCX_SLAB_MAP_MASK 0xffff0000 -#define NCX_SLAB_MAP_SHIFT 16 - -#define NCX_SLAB_BUSY 0xffffffff - -#else /* (NCX_PTR_SIZE == 8) */ - -#define NCX_SLAB_PAGE_FREE 0 -#define NCX_SLAB_PAGE_BUSY 0xffffffffffffffff -#define NCX_SLAB_PAGE_START 0x8000000000000000 - -#define NCX_SLAB_SHIFT_MASK 0x000000000000000f -#define NCX_SLAB_MAP_MASK 0xffffffff00000000 -#define NCX_SLAB_MAP_SHIFT 32 - -#define NCX_SLAB_BUSY 0xffffffffffffffff - -#endif - - -#if (NCX_DEBUG_MALLOC) - -#define ncx_slab_junk(p, size) ncx_memset(p, 0xA5, size) - -#else - -#define ncx_slab_junk(p, size) - -#endif - - -static ncx_slab_page_t *ncx_slab_alloc_pages(ncx_slab_pool_t *pool, - ncx_uint_t pages); -static void ncx_slab_free_pages(ncx_slab_pool_t *pool, ncx_slab_page_t *page, - ncx_uint_t pages); -static bool ncx_slab_empty(ncx_slab_pool_t *pool, ncx_slab_page_t *page); - -static ncx_uint_t ncx_slab_max_size; -static ncx_uint_t ncx_slab_exact_size; -static ncx_uint_t ncx_slab_exact_shift; -static ncx_uint_t ncx_pagesize; -static ncx_uint_t ncx_pagesize_shift; -static ncx_uint_t ncx_real_pages; - -void -ncx_slab_init(ncx_slab_pool_t *pool) -{ - u_char *p; - size_t size; - ncx_uint_t i, n, pages; - ncx_slab_page_t *slots; - - /* - * 初始化pagesize 为系统内存页大小,一般为4k - * pagesize = pow(2, pagesize_shift),即xxx_shift都是指幂指数 - * 一块page被切割成大小相等的内存块(下面的注释暂称为obj), - * 不同的page,被切割的obj大小可能不等,但obj的大小都是2的N次方分配的.即 8 16 32 ... - * */ - ncx_pagesize = getpagesize(); - for (n = ncx_pagesize, ncx_pagesize_shift = 0; - n >>= 1; ncx_pagesize_shift++) { /* void */ } - - /* - * slab_max_size ,即slab最大obj大小,默认为pagesize的一半 - * slab_exact_size, 一个临界值,这里暂不详细讨论,见下面的注释. - */ - if (ncx_slab_max_size == 0) { - ncx_slab_max_size = ncx_pagesize / 2; - ncx_slab_exact_size = ncx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ncx_slab_exact_size; n >>= 1; ncx_slab_exact_shift++) { - /* void */ - } - } - - /* - * 最小的obj大小,nginx默认使用8字节 - * 即min_shift 为最小obj大小的幂指数 <=> 8 = pow(2, 3) - */ - pool->min_size = 1 << pool->min_shift; - - p = (u_char *) pool + sizeof(ncx_slab_pool_t); - slots = (ncx_slab_page_t *) p; - - n = ncx_pagesize_shift - pool->min_shift; - - /* - * slots是page管理节点的头节点,一个slots链表(如slots[n])里的page的obj大小相等 - * slots[n].slab 是一个uintptr_t类型,在32位系统,与unsigned等价,即有32bit可用 - * slab字段在不同的使用场景下代表不同含义,这也是nginx slab巧妙的地方之一. - * 详细解释见下面注释. - */ - for (i = 0; i < n; i++) { - slots[i].slab = 0; - slots[i].next = &slots[i]; - slots[i].prev = 0; - } - - p += n * sizeof(ncx_slab_page_t); - - size = pool->end - p; - - /* - * 模拟脏数据,即每次alloc的内存都有脏数据 - */ - ncx_slab_junk(p, size); - - /* - * 每个page分割成相等大小的obj, 一个page对应一个管理节点 - * pages,即内存池的大小可分配多少个page - * 由于需要考虑内存对齐的问题,所以在init函数结尾会重新计算pages的大小 - * 所以,内存对齐会带来内存浪费(最大不超过pagesize*2),但也会带来很多惊喜... - */ - pages = (ncx_uint_t) (size / (ncx_pagesize + sizeof(ncx_slab_page_t))); - - ncx_memzero(p, pages * sizeof(ncx_slab_page_t)); - - pool->pages = (ncx_slab_page_t *) p; - - /* - * 1.free链表,连接所有空闲的page的管理节点 - * 2.slots链表,连接所有在用的,而且有可用obj的page的管理节点 - * 3.已没有空闲obj的page的管理节点,处于“悬空”状态,既不在free,也不在slots里. - * - * 所以情况3的page在内存池处于"不可见"状态,给应用层分配内存的时候不用再去查询此类page - * 只是在free,释放内存的时候,会被重新放到相应的slots链表,因为此时它又有可用节点了 - * - * 不管是free链表还是slots链表,连接的都是page对应的管理节点,page是存放实际数据的,与链表没有半点关系. - */ - pool->free.prev = 0; - pool->free.next = (ncx_slab_page_t *) p; - - /* - * pool->pages指向第一块page对应的管理节点 - * 此时slab字段表示的是连续的可用的page数量,初始化时候都为连续且可用,即为pages - * 所以对于未使用的page,其对应的管理节点的slab表示以该page开始,连续可用的page数量 - * 在使用的过程中,反复的分配、回收,可用的page之间是通过链表连接,在物理内存里并不一定是连续的 - */ - pool->pages->slab = pages; - pool->pages->next = &pool->free; - pool->pages->prev = (uintptr_t) &pool->free; - - /* - * start指向第一块page的首地址 - * 值得注意的是数据区首地址必须是pagesize对齐,后续很多操作都得益于内存对齐 - */ - pool->start = (u_char *) - ncx_align_ptr((uintptr_t) p + pages * sizeof(ncx_slab_page_t), - ncx_pagesize); - - /* - * 重新计算上一步内存对齐后,可用的page数量 - * 需要谨记的是page 与 page管理节点是一一对应的 - * 后续很多操作是根据page管理节点的下标来推算page页的实际地址. - */ - ncx_real_pages = (pool->end - pool->start) / ncx_pagesize; - pool->pages->slab = ncx_real_pages; -} - - -void * -ncx_slab_alloc(ncx_slab_pool_t *pool, size_t size) -{ - void *p; - - /* - * 提供了一个加锁接口,具体见ncx_lock.h - * - * 如果内存池是基于共享内存分配,并同时给多个进程共享 - * 则需实现一个进程级的自旋锁(可参考nginx的ngx_shmtx.c) - * - * 如果是多线程共享,则可使用线程级的自旋锁 - * 如 pthread_spin_lock - * - * 如果是私有内存,并且是单进程单线程模型 - * 则把ncx_shmtx_lock/unlock 可定义为空 - */ - ncx_shmtx_lock(&pool->mutex); - - p = ncx_slab_alloc_locked(pool, size); - - ncx_shmtx_unlock(&pool->mutex); - - return p; -} - - -void * -ncx_slab_alloc_locked(ncx_slab_pool_t *pool, size_t size) -{ - size_t s; - uintptr_t p, n, m, mask, *bitmap; - ncx_uint_t i, slot, shift, map; - ncx_slab_page_t *page, *prev, *slots; - - /* - * 如果需要分配的内存超过最大的obj大小,则以pagesize为单位进行整页分配 - */ - if (size >= ncx_slab_max_size) { - - debug("slab alloc: %zu", size); - - page = ncx_slab_alloc_pages(pool, (size >> ncx_pagesize_shift) - + ((size % ncx_pagesize) ? 1 : 0)); - - /* - * 由于每个page与其管理节点是一一对应的,所以根据管理节点的偏移,很容易可计算出page的首地址 - * 1 << ncx_pagesize_shift 是一个page的大小 - */ - if (page) { - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - - } else { - p = 0; - } - - goto done; - } - - /* - * 根据size,计算其对应哪个slot; - * 假设最小obj为8字节,最大obj为2048字节,则slab分9个规模,分别为 - * 8 16 32 64 128 256 512 1024 2048 - */ - if (size > pool->min_size) { - shift = 1; - for (s = size - 1; s >>= 1; shift++) { /* void */ } - slot = shift - pool->min_shift; - - } else { - size = pool->min_size; - shift = pool->min_shift; - slot = 0; - } - - /* - * 获取对应的page管理节点链表 - */ - slots = (ncx_slab_page_t *) ((u_char *) pool + sizeof(ncx_slab_pool_t)); - page = slots[slot].next; - - /* - * slab存在空闲obj - */ - if (page->next != page) { - - /* - * slab规模分为三种: - * 1. < ncx_slab_exact_shift - * 2. = ncx_slab_exact_shift - * 3. > ncx_slab_exact_shift - * - * 为什么要区分三类情况,这与ncx_slab_page_t.slab字段的使用直接相关; - * 在32位操作系统,slab大小是4字节,即32bit - * 对应以上三种情况,slab字段的使用分别是 - * 1.表示具体的obj大小,记录的是size_shift - * 2.pagesize/slab_exact_size 刚好为32,所以slab可以当作bitmap使用,表示page里哪些obj可用 - * 3.高(16)位是bitmap,低(16)位是记录块大小; - */ - if (shift < ncx_slab_exact_shift) { - - do { - /* - * < slab_exact_shift的情况,slab只用来记录obj的大小 - * 则page的bitmap就需要占用obj来存放 - */ - p = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t *) (pool->start + p); - - /* - * (1 << (ncx_pagesize_shift - shift)) 算出一个page存放的obj数目 - * / (sizeof(uintptr_t) * 8) 计算需要占用多少uintptr_t 来存储bitmap - * - * 即map 表示占用多少个uintptr_t(32bit系统占4字节,64bit占8字节) - */ - map = (1 << (ncx_pagesize_shift - shift)) - / (sizeof(uintptr_t) * 8); - - for (n = 0; n < map; n++) { - - /* - * 如果有空闲obj - */ - if (bitmap[n] != NCX_SLAB_BUSY) { - - /* - * 找出具体的空闲obj - * bit为0为空闲节点 - */ - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((bitmap[n] & m)) { - continue; - } - - /* - * 更新bitmap - */ - bitmap[n] |= m; - - /* - * 计算得出i为该空闲obj在page里的地址偏移 - * 可拆分为 (1<prev & ~NCX_SLAB_PAGE_MASK) 获取原始的prev的page的地址 - * nginx代码经常看到内存对齐,这么做会带来性能的提升,带同时会造成小部分内存浪费 - * 所以nginx很多时候会把某小部分信息,隐藏在地址里,通过简单的“或”,“与”运算来设置和还原. - * - * prev隐藏的信息是page对应的规模类型(small.exact,big.page).后面会详细讨论。 - */ - prev = (ncx_slab_page_t *) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - /* - * NCX_SLAB_SMALL 表示 < ncx_slab_exact_shift 的slab类型 - */ - page->next = NULL; - page->prev = NCX_SLAB_SMALL; - } - - /* - * 正如上述注释,i表示obj在该page(page)里的偏移 - */ - p = (uintptr_t) bitmap + i; - - goto done; - } - } - } - - page = page->next; - - } while (page); - - /* - * slab_exact 类型;假设pagesize为4096, - * 则slab_exact_size 为128 - */ - } else if (shift == ncx_slab_exact_shift) { - - do { - if (page->slab != NCX_SLAB_BUSY) { - - /* - * slab字段用作bitmap - * for循环是为了找到空闲的obj - */ - for (m = 1, i = 0; m; m <<= 1, i++) { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if (page->slab == NCX_SLAB_BUSY) { - prev = (ncx_slab_page_t *) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NCX_SLAB_EXACT; - } - - /* - * (page - pool->pages) << ncx_pagesize_shift 算出该page的首地址 - * i << shift 算出obj在page里的偏移 - * += pool->start 算出obj的首地址 - */ - p = (page - pool->pages) << ncx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - page = page->next; - - } while (page); - - } else { - /* - * > ncx_slab_exact_shift - * (page->slab & NCX_SLAB_SHIFT_MASK) => 取page对应的obj的size_shift - * 1 << n 算出page里存储的obj数 - * ((uintptr_t) 1 << n) - 1 => 算出bitmap 掩码 - * n << NCX_SLAB_MAP_SHIFT 因为是高位保存bitmap数据,所以需要掩码往高位移 - */ - n = ncx_pagesize_shift - (page->slab & NCX_SLAB_SHIFT_MASK); - n = 1 << n; - n = ((uintptr_t) 1 << n) - 1; - mask = n << NCX_SLAB_MAP_SHIFT; - - /* - * 接下来的操作与之前类似 - */ - do { - if ((page->slab & NCX_SLAB_MAP_MASK) != mask) { - - for (m = (uintptr_t) 1 << NCX_SLAB_MAP_SHIFT, i = 0; - m & mask; - m <<= 1, i++) - { - if ((page->slab & m)) { - continue; - } - - page->slab |= m; - - if ((page->slab & NCX_SLAB_MAP_MASK) == mask) { - prev = (ncx_slab_page_t *) - (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - - page->next = NULL; - page->prev = NCX_SLAB_BIG; - } - - p = (page - pool->pages) << ncx_pagesize_shift; - p += i << shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - page = page->next; - - } while (page); - } - } - - /* - * 如果slots链表为空,即没有可用的pagee - * 则重新分配一个page,并把其管理节点放到slots链表 - */ - page = ncx_slab_alloc_pages(pool, 1); - - if (page) { - if (shift < ncx_slab_exact_shift) { - p = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t *) (pool->start + p); - - /* - * n为需要多少个obj用来存放bitmap - */ - s = 1 << shift; - n = (1 << (ncx_pagesize_shift - shift)) / 8 / s; - - if (n == 0) { - n = 1; - } - - /* - * 正如上述所说,n代表占用多少个obj来存放bitmap - * 所以,bitmap[0]初始化需要把占用的obj对应的bit置为1 - */ - bitmap[0] = (2 << n) - 1; - - /* - * map为bitmap所覆盖的uintptr_t数 - */ - map = (1 << (ncx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); - - for (i = 1; i < map; i++) { - bitmap[i] = 0; - } - - /* - * 把新分配的page对应的管理节点放到slots链表 - * (uintptr_t) &slots[slot] | NCX_SLAB_SMALL,在prev字段里保存了slab的规模(small,exact,big,page四类) - * 这样做的好处主要是简化了free的逻辑;在free函数再详细讨论 - */ - page->slab = shift; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_SMALL; - - slots[slot].next = page; - - p = ((page - pool->pages) << ncx_pagesize_shift) + s * n; - p += (uintptr_t) pool->start; - - goto done; - - } else if (shift == ncx_slab_exact_shift) { - - page->slab = 1; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_EXACT; - - slots[slot].next = page; - - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - - goto done; - - } else { /* shift > ncx_slab_exact_shift */ - - page->slab = ((uintptr_t) 1 << NCX_SLAB_MAP_SHIFT) | shift; - page->next = &slots[slot]; - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_BIG; - - slots[slot].next = page; - - p = (page - pool->pages) << ncx_pagesize_shift; - p += (uintptr_t) pool->start; - - goto done; - } - } - - p = 0; - -done: - - debug("slab alloc: %p", (void *)p); - - return (void *) p; -} - - -void -ncx_slab_free(ncx_slab_pool_t *pool, void *p) -{ - ncx_shmtx_lock(&pool->mutex); - - ncx_slab_free_locked(pool, p); - - ncx_shmtx_unlock(&pool->mutex); -} - - -void -ncx_slab_free_locked(ncx_slab_pool_t *pool, void *p) -{ - size_t size; - uintptr_t slab, m, *bitmap; - ncx_uint_t n, type, slot, shift, map; - ncx_slab_page_t *slots, *page; - - debug("slab free: %p", p); - - if ((u_char *) p < pool->start || (u_char *) p > pool->end) { - error("ncx_slab_free(): outside of pool"); - goto fail; - } - - /* - * 算出p所在的是第n块page - * type 为page里obj的规模: - * 1. SMALL 即 < slab_exact_size - * 2. EXACT 即 = slab_exact_size - * 3. BIG 即 > slab_exact_size && < max_slab_size - * 4. PAGE 即 > max_slab_size - * - * 不同的规模,free逻辑会不一样,看下面的注释 - */ - n = ((u_char *) p - pool->start) >> ncx_pagesize_shift; - page = &pool->pages[n]; - slab = page->slab; - type = page->prev & NCX_SLAB_PAGE_MASK; - - switch (type) { - - case NCX_SLAB_SMALL: - - /* - * slab保存的是obj的大小的shift - */ - shift = slab & NCX_SLAB_SHIFT_MASK; - size = 1 << shift; - - /* - * 得益于内存对齐,可做合法性弱校验 - */ - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - /* - * 1.算出p对应page里的第n个obj - * 2.算出obj所对应某块(具体哪块是步骤3算出)bitmap的第m个bit - * 3.算出obj所在的是哪块bitmap(一个uintptr_t为一块bitmap) - * 4.算出bitmap的首地址(即第一块bitmap的地址) - */ - n = ((uintptr_t) p & (ncx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); - n /= (sizeof(uintptr_t) * 8); - bitmap = (uintptr_t *) ((uintptr_t) p & ~(ncx_pagesize - 1)); - - /* - * 检测是否对应的bit被置位了,如果否,则直接返回已释放 - * 避免重复释放带来副作用 - */ - if (bitmap[n] & m) { - - /* - * 如果是free以后使得page由busy=>可用, - * 则把该page重新放到slots链表管理 - */ - if (page->next == NULL) { - slots = (ncx_slab_page_t *) - ((u_char *) pool + sizeof(ncx_slab_pool_t)); - slot = shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_SMALL; - page->next->prev = (uintptr_t) page | NCX_SLAB_SMALL; - } - - bitmap[n] &= ~m; - - /* - * 算出bitmap占用n个obj - */ - n = (1 << (ncx_pagesize_shift - shift)) / 8 / (1 << shift); - - if (n == 0) { - n = 1; - } - - /* - * 检查该page是否完全空闲,即是否还有已用obj - * 如果没有,则把page重新放回free链表 - */ - if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { - goto done; - } - - map = (1 << (ncx_pagesize_shift - shift)) / (sizeof(uintptr_t) * 8); - - for (n = 1; n < map; n++) { - if (bitmap[n]) { - goto done; - } - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_EXACT: - - /* - * p对应bitmap的第m个bit - */ - m = (uintptr_t) 1 << - (((uintptr_t) p & (ncx_pagesize - 1)) >> ncx_slab_exact_shift); - size = ncx_slab_exact_size; - - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - if (slab & m) { - if (slab == NCX_SLAB_BUSY) { - slots = (ncx_slab_page_t *) - ((u_char *) pool + sizeof(ncx_slab_pool_t)); - slot = ncx_slab_exact_shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_EXACT; - page->next->prev = (uintptr_t) page | NCX_SLAB_EXACT; - } - - page->slab &= ~m; - - if (page->slab) { - goto done; - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_BIG: - - shift = slab & NCX_SLAB_SHIFT_MASK; - size = 1 << shift; - - if ((uintptr_t) p & (size - 1)) { - goto wrong_chunk; - } - - /* - * (((uintptr_t) p & (ncx_pagesize - 1)) >> shift) 算出对应bitmap哪个bit - */ - m = (uintptr_t) 1 << ((((uintptr_t) p & (ncx_pagesize - 1)) >> shift) - + NCX_SLAB_MAP_SHIFT); - - if (slab & m) { - - if (page->next == NULL) { - slots = (ncx_slab_page_t *) - ((u_char *) pool + sizeof(ncx_slab_pool_t)); - slot = shift - pool->min_shift; - - page->next = slots[slot].next; - slots[slot].next = page; - - page->prev = (uintptr_t) &slots[slot] | NCX_SLAB_BIG; - page->next->prev = (uintptr_t) page | NCX_SLAB_BIG; - } - - page->slab &= ~m; - - if (page->slab & NCX_SLAB_MAP_MASK) { - goto done; - } - - ncx_slab_free_pages(pool, page, 1); - - goto done; - } - - goto chunk_already_free; - - case NCX_SLAB_PAGE: - - if ((uintptr_t) p & (ncx_pagesize - 1)) { - goto wrong_chunk; - } - - if (slab == NCX_SLAB_PAGE_FREE) { - alert("ncx_slab_free(): page is already free"); - goto fail; - } - - if (slab == NCX_SLAB_PAGE_BUSY) { - alert("ncx_slab_free(): pointer to wrong page"); - goto fail; - } - - n = ((u_char *) p - pool->start) >> ncx_pagesize_shift; - size = slab & ~NCX_SLAB_PAGE_START; - - ncx_slab_free_pages(pool, &pool->pages[n], size); - - ncx_slab_junk(p, size << ncx_pagesize_shift); - - return; - } - - /* not reached */ - - return; - -done: - - ncx_slab_junk(p, size); - - return; - -wrong_chunk: - - error("ncx_slab_free(): pointer to wrong chunk"); - - goto fail; - -chunk_already_free: - - error("ncx_slab_free(): chunk is already free"); - -fail: - - return; -} - - -static ncx_slab_page_t * -ncx_slab_alloc_pages(ncx_slab_pool_t *pool, ncx_uint_t pages) -{ - ncx_slab_page_t *page, *p; - - for (page = pool->free.next; page != &pool->free; page = page->next) { - - /* - * 上面提到过,对于空闲的page,其对应的管理节点的slab字段表示以该page开始,连续可用的page数 - * 值得注意的是,如果可用的空闲内存(page)总和超过size,但是由于不是连续的,也会导致分配失败 - * nginx定义上的连续并不严谨,即有可能把实际上连续内存当作非连续看待 - * 对于上面问题的理解,建议结合本人博客 http://www.dcshi.com/?p=360 m的图例理解 - */ - if (page->slab >= pages) { - - /* - * 如果连续的page数比pages要大,进行分割,把剩余的page放回free链表里 - */ - if (page->slab > pages) { - /* - * 连续的page数要 减去 pages - */ - page[pages].slab = page->slab - pages; - page[pages].next = page->next; - page[pages].prev = page->prev; - - p = (ncx_slab_page_t *) page->prev; - p->next = &page[pages]; - page->next->prev = (uintptr_t) &page[pages]; - - } else { - p = (ncx_slab_page_t *) page->prev; - p->next = page->next; - page->next->prev = page->prev; - } - - /* - * slab使用: - * 对于整page分配的情况,slab 记录两个信息 - * 1.标识是整page分配,即 NCX_SLAB_PAGE_START - * 2.标识本次分配的page数量, 即pages - * - * next,prev 两个指针都处于悬空状态,会导致出现"野指针"的问题么? - * 肯定是不会的,只需要free的时候把其放回free链表即可. - */ - page->slab = pages | NCX_SLAB_PAGE_START; - page->next = NULL; - page->prev = NCX_SLAB_PAGE; - - if (--pages == 0) { - return page; - } - - /* - * 一次分配超过一个page,则需要把第一块以外page对应的管理结构也进行更新 - */ - for (p = page + 1; pages; pages--) { - p->slab = NCX_SLAB_PAGE_BUSY; - p->next = NULL; - p->prev = NCX_SLAB_PAGE; - p++; - } - - return page; - } - } - - error("ncx_slab_alloc() failed: no memory"); - - return NULL; -} - - -static void -ncx_slab_free_pages(ncx_slab_pool_t *pool, ncx_slab_page_t *page, - ncx_uint_t pages) -{ - ncx_slab_page_t *prev, *next; - - if (pages > 1) { - ncx_memzero(&page[1], (pages - 1) * sizeof(ncx_slab_page_t)); - } - - if (page->next) { - prev = (ncx_slab_page_t *) (page->prev & ~NCX_SLAB_PAGE_MASK); - prev->next = page->next; - page->next->prev = page->prev; - } - - page->slab = pages; - /* - * 把回收的page重新放到free链表 - */ - page->prev = (uintptr_t) &pool->free; - page->next = pool->free.next; - - page->next->prev = (uintptr_t) page; - - pool->free.next = page; - -#ifdef PAGE_MERGE - if (pool->pages != page) { - prev = page - 1; - if (ncx_slab_empty(pool, prev)) { - for (; prev >= pool->pages; prev--) { - if (prev->slab != 0) - { - pool->free.next = page->next; - page->next->prev = (uintptr_t) &pool->free; - - prev->slab += pages; - ncx_memzero(page, sizeof(ncx_slab_page_t)); - - page = prev; - - break; - } - } - } - } - - if ((page - pool->pages + page->slab) < ncx_real_pages) { - next = page + page->slab; - if (ncx_slab_empty(pool, next)) - { - prev = (ncx_slab_page_t *) (next->prev); - prev->next = next->next; - next->next->prev = next->prev; - - page->slab += next->slab; - ncx_memzero(next, sizeof(ncx_slab_page_t)); - } - } - -#endif -} - -void -ncx_slab_dummy_init(ncx_slab_pool_t *pool) -{ - ncx_uint_t n; - - /* - * 内存池基于共享内存实现的场景 - * 外部进程attch同一块内存不需要重新初始化ncx_slab_pool_t - */ - - ncx_pagesize = getpagesize(); - for (n = ncx_pagesize, ncx_pagesize_shift = 0; - n >>= 1; ncx_pagesize_shift++) { /* void */ } - - if (ncx_slab_max_size == 0) { - ncx_slab_max_size = ncx_pagesize / 2; - ncx_slab_exact_size = ncx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ncx_slab_exact_size; n >>= 1; ncx_slab_exact_shift++) { - /* void */ - } - } -} - -void -ncx_slab_stat(ncx_slab_pool_t *pool, ncx_slab_stat_t *stat) -{ - uintptr_t m, n, mask, slab; - uintptr_t *bitmap; - ncx_uint_t i, j, map, type, obj_size; - ncx_slab_page_t *page; - - ncx_memzero(stat, sizeof(ncx_slab_stat_t)); - - page = pool->pages; - stat->pages = (pool->end - pool->start) / ncx_pagesize;; - - for (i = 0; i < stat->pages; i++) - { - slab = page->slab; - type = page->prev & NCX_SLAB_PAGE_MASK; - - switch (type) { - - case NCX_SLAB_SMALL: - - n = (page - pool->pages) << ncx_pagesize_shift; - bitmap = (uintptr_t *) (pool->start + n); - - obj_size = 1 << slab; - map = (1 << (ncx_pagesize_shift - slab)) - / (sizeof(uintptr_t) * 8); - - for (j = 0; j < map; j++) { - for (m = 1 ; m; m <<= 1) { - if ((bitmap[j] & m)) { - stat->used_size += obj_size; - stat->b_small += obj_size; - } - - } - } - - stat->p_small++; - - break; - - case NCX_SLAB_EXACT: - - if (slab == NCX_SLAB_BUSY) { - stat->used_size += sizeof(uintptr_t) * 8 * ncx_slab_exact_size; - stat->b_exact += sizeof(uintptr_t) * 8 * ncx_slab_exact_size; - } - else { - for (m = 1; m; m <<= 1) { - if (slab & m) { - stat->used_size += ncx_slab_exact_size; - stat->b_exact += ncx_slab_exact_size; - } - } - } - - stat->p_exact++; - - break; - - case NCX_SLAB_BIG: - - j = ncx_pagesize_shift - (slab & NCX_SLAB_SHIFT_MASK); - j = 1 << j; - j = ((uintptr_t) 1 << j) - 1; - mask = j << NCX_SLAB_MAP_SHIFT; - obj_size = 1 << (slab & NCX_SLAB_SHIFT_MASK); - - for (m = (uintptr_t) 1 << NCX_SLAB_MAP_SHIFT; m & mask; m <<= 1) - { - if ((page->slab & m)) { - stat->used_size += obj_size; - stat->b_big += obj_size; - } - } - - stat->p_big++; - - break; - - case NCX_SLAB_PAGE: - - if (page->prev == NCX_SLAB_PAGE) { - slab = slab & ~NCX_SLAB_PAGE_START; - stat->used_size += slab * ncx_pagesize; - stat->b_page += slab * ncx_pagesize; - stat->p_page += slab; - - i += (slab - 1); - - break; - } - - default: - - if (slab > stat->max_free_pages) { - stat->max_free_pages = page->slab; - } - - stat->free_page += slab; - - i += (slab - 1); - - break; - } - - page = pool->pages + i + 1; - } - - stat->pool_size = pool->end - pool->start; - stat->used_pct = stat->used_size * 100 / stat->pool_size; - - info("pool_size : %zu bytes", stat->pool_size); - info("used_size : %zu bytes", stat->used_size); - info("used_pct : %zu%%\n", stat->used_pct); - - info("total page count : %zu", stat->pages); - info("free page count : %zu\n", stat->free_page); - - info("small slab use page : %zu,\tbytes : %zu", stat->p_small, stat->b_small); - info("exact slab use page : %zu,\tbytes : %zu", stat->p_exact, stat->b_exact); - info("big slab use page : %zu,\tbytes : %zu", stat->p_big, stat->b_big); - info("page slab use page : %zu,\tbytes : %zu\n", stat->p_page, stat->b_page); - - info("max free pages : %zu\n", stat->max_free_pages); -} - -static bool -ncx_slab_empty(ncx_slab_pool_t *pool, ncx_slab_page_t *page) -{ - ncx_slab_page_t *prev; - - if (page->slab == 0) { - return true; - } - - //page->prev == PAGE | SMALL | EXACT | BIG - if (page->next == NULL ) { - return false; - } - - prev = (ncx_slab_page_t *)(page->prev & ~NCX_SLAB_PAGE_MASK); - while (prev >= pool->pages) { - prev = (ncx_slab_page_t *)(prev->prev & ~NCX_SLAB_PAGE_MASK); - }; - - if (prev == &pool->free) { - return true; - } - - return false; -} diff --git a/third_party/mempool/mempool/ncx_slab.h b/third_party/mempool/mempool/ncx_slab.h deleted file mode 100644 index b13e4ca..0000000 --- a/third_party/mempool/mempool/ncx_slab.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "ncx_core.h" -#include "ncx_lock.h" - -#include "extern.h" - -typedef struct ncx_slab_page_s ncx_slab_page_t; - -struct ncx_slab_page_s { - uintptr_t slab; - ncx_slab_page_t *next; - uintptr_t prev; -}; - - -typedef struct { - size_t min_size; - size_t min_shift; - - ncx_slab_page_t *pages; - ncx_slab_page_t free; - - u_char *start; - u_char *end; - - ncx_shmtx_t mutex; - - void *addr; -} ncx_slab_pool_t; - -typedef struct { - size_t pool_size, used_size, used_pct; - size_t pages, free_page; - size_t p_small, p_exact, p_big, p_page; /* 四种slab占用的page数 */ - size_t b_small, b_exact, b_big, b_page; /* 四种slab占用的byte数 */ - size_t max_free_pages; /* 最大的连续可用page数 */ -} ncx_slab_stat_t; - -#ifdef __cplusplus -extern "C" { // only need to export C interface if - // used by C++ source code -#endif - -MEMPOOL_API void ncx_slab_init(ncx_slab_pool_t *pool); -MEMPOOL_API void* ncx_slab_alloc(ncx_slab_pool_t *pool, size_t size); -MEMPOOL_API void* ncx_slab_alloc_locked(ncx_slab_pool_t *pool, size_t size); -MEMPOOL_API void ncx_slab_free(ncx_slab_pool_t *pool, void *p); -MEMPOOL_API void ncx_slab_free_locked(ncx_slab_pool_t *pool, void *p); - -MEMPOOL_API void ncx_slab_dummy_init(ncx_slab_pool_t *pool); -MEMPOOL_API void ncx_slab_stat(ncx_slab_pool_t *pool, ncx_slab_stat_t *stat); - -#ifdef __cplusplus -} -#endif diff --git a/third_party/taskflow b/third_party/taskflow index fc27de3..598fa70 160000 --- a/third_party/taskflow +++ b/third_party/taskflow @@ -1 +1 @@ -Subproject commit fc27de3eae7d35ec3a7dea6ab37da786d7ccacdb +Subproject commit 598fa70633c10b2ae7354b976b4976bf40502405