This commit is contained in:
codeboss 2025-09-11 18:36:49 +08:00
commit e83cf9b7ce
10 changed files with 518 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
x64/
.vs/

25
ECSMemoryPool.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35825.156 d17.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ECSMemoryPool", "ECSMemoryPool\ECSMemoryPool.vcxproj", "{666EC5D6-70A6-40DA-B92A-364116921A07}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{666EC5D6-70A6-40DA-B92A-364116921A07}.Debug|x64.ActiveCfg = Debug|x64
{666EC5D6-70A6-40DA-B92A-364116921A07}.Debug|x64.Build.0 = Debug|x64
{666EC5D6-70A6-40DA-B92A-364116921A07}.Release|x64.ActiveCfg = Release|x64
{666EC5D6-70A6-40DA-B92A-364116921A07}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A821C833-A8F8-4557-AAEC-84F9281C171F}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{666EC5D6-70A6-40DA-B92A-364116921A07}</ProjectGuid>
<Keyword>QtVS_v304</Keyword>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">10.0</WindowsTargetPlatformVersion>
<QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
<Import Project="$(QtMsBuild)\qt_defaults.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="QtSettings">
<QtInstall>5.12.11_msvc2017_64</QtInstall>
<QtModules>core</QtModules>
<QtBuildConfig>debug</QtBuildConfig>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="QtSettings">
<QtInstall>5.12.11_msvc2017_64</QtInstall>
<QtModules>core</QtModules>
<QtBuildConfig>release</QtBuildConfig>
</PropertyGroup>
<Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
<Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
</Target>
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="Shared" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(QtMsBuild)\Qt.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>ECSMEMORYPOOL_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'" Label="Configuration">
<ClCompile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>ECSMEMORYPOOL_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="memory_pages.cpp" />
<ClInclude Include="ecsmemorypool_global.h" />
<ClInclude Include="ecs_memorypool.h" />
<ClCompile Include="ecs_memorypool.cpp" />
<ClInclude Include="memory_pages.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')">
<Import Project="$(QtMsBuild)\qt.targets" />
</ImportGroup>
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Form Files">
<UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier>
<Extensions>ui</Extensions>
</Filter>
<Filter Include="Translation Files">
<UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier>
<Extensions>ts</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ecsmemorypool_global.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClCompile Include="ecs_memorypool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClInclude Include="ecs_memorypool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memory_pages.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="memory_pages.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
<PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<QtTouchProperty>
</QtTouchProperty>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,5 @@
#include "ecs_memorypool.h"
ECSMemoryPool::ECSMemoryPool()
{
}

View File

@ -0,0 +1,28 @@
#pragma once
#include "ecsmemorypool_global.h"
#include <QJsonObject>
#include <QList>
#include <QHash>
#include <memory_pages.h>
template<typename T>
concept CompenentType = requires(T t, const QJsonObject &in, QJsonObject out){
{ T::typeCode() } -> std::same_as<uint64_t>;
{ T::typeSize() } -> std::same_as<uint32_t>;
{ t.loadFrom(in) } -> std::same_as<void>;
{ t.saveTo(out) } -> std::same_as<void>;
};
class ECSMEMORYPOOL_EXPORT ECSMemoryPool{
private:
QList<std::shared_ptr<MemoryPage>> _storage_pages;
public:
ECSMemoryPool();
template<CompenentType T> void registerComponent() {
}
};

View File

@ -0,0 +1,13 @@
#pragma once
#include <QtCore/qglobal.h>
#ifndef BUILD_STATIC
# if defined(ECSMEMORYPOOL_LIB)
# define ECSMEMORYPOOL_EXPORT Q_DECL_EXPORT
# else
# define ECSMEMORYPOOL_EXPORT Q_DECL_IMPORT
# endif
#else
# define ECSMEMORYPOOL_EXPORT
#endif

View File

@ -0,0 +1,130 @@
#include "memory_pages.h"
MemoryPage::MemoryPage(uint16_t element_size, uint64_t typecode)
{
pcb.byte_count_per_element = element_size;
pcb.total_buffer_size = sizeof(data_buffer);
pcb.typecode_of_element = typecode;
}
void MemoryPage::accessRecord(uint64_t timepoint_usec) {
std::lock_guard<std::mutex> g(pcb.access_protected);
pcb.curr_access_usec = timepoint_usec;
pcb.acc_count_per_cycle++;
}
uint32_t MemoryPage::timesClear() {
std::lock_guard<std::mutex> g(pcb.access_protected);
auto value = pcb.acc_count_per_cycle;
pcb.acc_count_per_cycle = 0;
return value;
}
std::pair<uint64_t, uint32_t> MemoryPage::getRecords() const {
auto data_ptr = const_cast<MemoryPage*>(this);
std::lock_guard<std::mutex> g(data_ptr->pcb.access_protected);
return std::make_pair(pcb.curr_access_usec, pcb.acc_count_per_cycle);
}
char* MemoryPage::getElementPtr(int index) {
auto member_cnt = elementCount();
auto element_size = elementSize();
char* element_ptr = nullptr;
if (index >= 0 && index < member_cnt) {
element_ptr = data_buffer + index * element_size;
}
else if (index < 0 && index >= -member_cnt) {
element_ptr = data_buffer + (member_cnt + index) * element_size;
}
lock();
if (element_ptr) {
auto data_ptr = (ElementControlBlock*)element_ptr;
data_ptr->page_refer = this;
data_ptr->element_index = index;
}
release();
return element_ptr;
}
void MemoryPage::lock()
{
pcb.access_protected.lock();
}
void MemoryPage::release() {
#pragma warning(push)
#pragma warning(disable : 26110)
pcb.access_protected.unlock();
#pragma warning(pop)
}
uint64_t MemoryPage::elementTypeCode() const
{
auto data_ptr = const_cast<MemoryPage*>(this);
std::lock_guard<std::mutex> g(data_ptr->pcb.access_protected);
return pcb.typecode_of_element;
}
uint16_t MemoryPage::elementSize() const {
auto data_ptr = const_cast<MemoryPage*>(this);
std::lock_guard<std::mutex> g(data_ptr->pcb.access_protected);
return pcb.byte_count_per_element;
}
uint16_t MemoryPage::elementCount() const {
uint16_t cnt = sizeof(data_buffer);
return cnt / this->elementSize();
}
uint32_t MemoryElement::validOffset()
{
uint32_t remains = sizeof(ElementControlBlock) % 8;
uint32_t times = sizeof(ElementControlBlock) / 8;
return (remains ? times + 1 : times) * 8;
}
uint32_t MemoryElement::rawSize(uint32_t data_type_size)
{
uint32_t minimal_size = validOffset() + data_type_size;
auto remains = minimal_size % 16;
auto times = minimal_size / 16;
return (remains ? times + 1 : times) * 16;
}
MemoryElement::MemoryElement(char* access_bind)
: data_ptr((ElementControlBlock*)access_bind) {
buffer_offset = validOffset();
}
void MemoryElement::accessRecUpdate(uint64_t time_usec)
{
data_ptr->page_refer->accessRecord(time_usec);
}
uint8_t MemoryElement::isActived() const
{
data_ptr->page_refer->lock();
auto mark = data_ptr->active_mark;
data_ptr->page_refer->release();
return mark;
}
void MemoryElement::setActive(uint8_t ste)
{
data_ptr->page_refer->lock();
data_ptr->active_mark = ste;
data_ptr->page_refer->release();
}
char* MemoryElement::dataLock()
{
data_ptr->page_refer->lock();
return ((char*)data_ptr) + buffer_offset;
}
void MemoryElement::release()
{
data_ptr->page_refer->release();
}

View File

@ -0,0 +1,145 @@
#pragma once
#include <mutex>
class MemoryPage;
/// <summary>
/// 内存页访问控制块
/// </summary>
struct PageControlBlock {
uint16_t active_entities_count = 0; // 活跃element数量决定是否需要卸载
uint16_t byte_count_per_element = 32; // 单个element大小16的倍数
uint32_t total_buffer_size = 0; // 可用数据缓冲区大小
uint64_t typecode_of_element = 0; // 元素类型标识码
uint64_t curr_access_usec = 0; // 最近访问时间点lsbus
uint32_t acc_count_per_cycle = 0; // 单周期内累积访问次数
uint32_t un_used = 0;
std::mutex access_protected; // 内存数据访问保护锁
};
/// <summary>
/// 内存页面16K大小
/// </summary>
class MemoryPage {
private:
PageControlBlock pcb;
char data_buffer[16 * 1024 - (sizeof(PageControlBlock) / 8 + 1) * 8] = {};
public:
/// <summary>
/// 构建内存页
/// </summary>
/// <param name="raw_element_size_16B">原始element尺寸</param>
explicit MemoryPage(uint16_t raw_element_size_16B, uint64_t typecode);
/// <summary>
/// 记录单次访问时间
/// </summary>
/// <param name="timepoint_usec"></param>
void accessRecord(uint64_t timepoint_usec);
/// <summary>
/// 清除访问次数记录
/// </summary>
/// <returns>上一周期累积次数</returns>
uint32_t timesClear();
/// <summary>
/// 获取访问记录
/// </summary>
/// <returns>{最近访问时间,累积次数}</returns>
std::pair<uint64_t, uint32_t> getRecords() const;
/// <summary>
/// 加锁在release之前不能访问本类型任何接口否则会造成死锁
/// </summary>
void lock();
/// <summary>
/// 解锁
/// </summary>
void release();
/// <summary>
/// 获取element元素数据访问指针
/// </summary>
/// <param name="index">元素索引</param>
/// <param name="active_set">是否设置</param>
/// <returns>数据指针</returns>
char* getElementPtr(int index);
/// <summary>
/// 元素类型码
/// </summary>
/// <returns></returns>
uint64_t elementTypeCode() const;
/// <summary>
/// 获取单个元素尺寸
/// </summary>
/// <returns>字节数量</returns>
uint16_t elementSize() const;
/// <summary>
/// 获取元素数量
/// </summary>
/// <returns></returns>
uint16_t elementCount() const;
};
/// <summary>
/// 元素访问控制块
/// </summary>
struct ElementControlBlock {
uint8_t active_mark = 0; // 活跃标志
uint8_t backup_1 = 0;
uint16_t byte_count = 16; // 该元素字节长度16的倍数
uint16_t element_index = 0; // 本元素在Page中的索引
uint16_t backup_2 = 0;
MemoryPage* page_refer = nullptr; // 页面关联指针
void* extend_bind = nullptr; // 绑定控制块内存指针
};
/// <summary>
/// 内存元素访问接口
/// </summary>
class MemoryElement {
private:
ElementControlBlock* const data_ptr;
uint32_t buffer_offset = 0;
public:
static uint32_t validOffset();
static uint32_t rawSize(uint32_t data_type_size);
/// <summary>
/// 构建内存元素访问接口
/// </summary>
/// <param name="access_bind"></param>
MemoryElement(char* access_bind);
/// <summary>
/// 更新最终访问时间
/// </summary>
/// <param name="time_usec"></param>
void accessRecUpdate(uint64_t time_usec);
/// <summary>
/// 数据活跃状态
/// </summary>
/// <returns></returns>
uint8_t isActived() const;
/// <summary>
/// 设置数据活跃状态
/// </summary>
/// <param name="ste"></param>
void setActive(uint8_t ste);
/// <summary>
/// 锁定数据,返回数据存储内存指针
/// </summary>
/// <returns></returns>
char* dataLock();
/// <summary>
/// 解锁数据
/// </summary>
void release();
};