aboutsummaryrefslogtreecommitdiff
path: root/src/zencore
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-03-06 16:18:32 +0100
committerGitHub Enterprise <[email protected]>2025-03-06 16:18:32 +0100
commit920120bbcec9f91df3336f62970b3e010a4fa6c2 (patch)
tree363460fbb90da8d1f8f0172483a7f5ffe22ea9f9 /src/zencore
parent5.6.0 (diff)
downloadzen-920120bbcec9f91df3336f62970b3e010a4fa6c2.tar.xz
zen-920120bbcec9f91df3336f62970b3e010a4fa6c2.zip
reduced memory churn using fixed_xxx containers (#236)
* Added EASTL to help with eliminating memory allocations * Applied EASTL to eliminate memory allocations, primarily by using `fixed_vector` et al to use stack allocations / inline struct allocations Reduces memory events in traces by close to a factor of 10 in test scenario (starting editor for project F)
Diffstat (limited to 'src/zencore')
-rw-r--r--src/zencore/compactbinary.cpp10
-rw-r--r--src/zencore/compactbinarybuilder.cpp11
-rw-r--r--src/zencore/compactbinarypackage.cpp14
-rw-r--r--src/zencore/include/zencore/compactbinarybuilder.h8
-rw-r--r--src/zencore/include/zencore/compactbinarypackage.h15
-rw-r--r--src/zencore/include/zencore/compositebuffer.h38
-rw-r--r--src/zencore/include/zencore/eastlutil.h20
-rw-r--r--src/zencore/include/zencore/memory/newdelete.h26
-rw-r--r--src/zencore/xmake.lua1
9 files changed, 120 insertions, 23 deletions
diff --git a/src/zencore/compactbinary.cpp b/src/zencore/compactbinary.cpp
index adccaba70..b43cc18f1 100644
--- a/src/zencore/compactbinary.cpp
+++ b/src/zencore/compactbinary.cpp
@@ -15,6 +15,8 @@
#include <zencore/testing.h>
#include <zencore/uid.h>
+#include <EASTL/fixed_vector.h>
+
#include <fmt/format.h>
#include <string_view>
@@ -1376,9 +1378,9 @@ TryMeasureCompactBinary(MemoryView View, CbFieldType& OutType, uint64_t& OutSize
CbField
LoadCompactBinary(BinaryReader& Ar, BufferAllocator Allocator)
{
- std::vector<uint8_t> HeaderBytes;
- CbFieldType FieldType;
- uint64_t FieldSize = 1;
+ eastl::fixed_vector<uint8_t, 32> HeaderBytes;
+ CbFieldType FieldType;
+ uint64_t FieldSize = 1;
for (const int64_t StartPos = Ar.CurrentOffset(); FieldSize > 0;)
{
@@ -1393,7 +1395,7 @@ LoadCompactBinary(BinaryReader& Ar, BufferAllocator Allocator)
HeaderBytes.resize(ReadOffset + ReadSize);
Ar.Read(HeaderBytes.data() + ReadOffset, ReadSize);
- if (TryMeasureCompactBinary(MakeMemoryView(HeaderBytes), FieldType, FieldSize))
+ if (TryMeasureCompactBinary(MakeMemoryView(HeaderBytes.data(), HeaderBytes.size()), FieldType, FieldSize))
{
if (FieldSize <= uint64_t(Ar.Size() - StartPos))
{
diff --git a/src/zencore/compactbinarybuilder.cpp b/src/zencore/compactbinarybuilder.cpp
index a60de023d..63c0b9c5c 100644
--- a/src/zencore/compactbinarybuilder.cpp
+++ b/src/zencore/compactbinarybuilder.cpp
@@ -15,23 +15,21 @@
namespace zen {
-template<typename T>
uint64_t
-AddUninitialized(std::vector<T>& Vector, uint64_t Count)
+AddUninitialized(CbWriter::CbWriterData_t& Vector, uint64_t Count)
{
const uint64_t Offset = Vector.size();
Vector.resize(Offset + Count);
return Offset;
}
-template<typename T>
uint64_t
-Append(std::vector<T>& Vector, const T* Data, uint64_t Count)
+Append(CbWriter::CbWriterData_t& Vector, const uint8_t* Data, uint64_t Count)
{
const uint64_t Offset = Vector.size();
Vector.resize(Offset + Count);
- memcpy(Vector.data() + Offset, Data, sizeof(T) * Count);
+ memcpy(Vector.data() + Offset, Data, sizeof(uint8_t) * Count);
return Offset;
}
@@ -76,7 +74,7 @@ IsUniformType(const CbFieldType Type)
/** Append the payload from the compact binary value to the array and return its type. */
static inline CbFieldType
-AppendCompactBinary(const CbFieldView& Value, std::vector<uint8_t>& OutData)
+AppendCompactBinary(const CbFieldView& Value, CbWriter::CbWriterData_t& OutData)
{
struct FCopy : public CbFieldView
{
@@ -93,7 +91,6 @@ AppendCompactBinary(const CbFieldView& Value, std::vector<uint8_t>& OutData)
CbWriter::CbWriter()
{
- States.reserve(4);
States.emplace_back();
}
diff --git a/src/zencore/compactbinarypackage.cpp b/src/zencore/compactbinarypackage.cpp
index 7de161845..ffe64f2e9 100644
--- a/src/zencore/compactbinarypackage.cpp
+++ b/src/zencore/compactbinarypackage.cpp
@@ -3,10 +3,13 @@
#include "zencore/compactbinarypackage.h"
#include <zencore/compactbinarybuilder.h>
#include <zencore/compactbinaryvalidation.h>
+#include <zencore/eastlutil.h>
#include <zencore/endian.h>
#include <zencore/stream.h>
#include <zencore/testing.h>
+#include <EASTL/span.h>
+
namespace zen {
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -341,6 +344,12 @@ CbPackage::SetObject(CbObject InObject, const IoHash* InObjectHash, AttachmentRe
}
void
+CbPackage::ReserveAttachments(size_t Count)
+{
+ Attachments.reserve(Count);
+}
+
+void
CbPackage::AddAttachment(const CbAttachment& Attachment, AttachmentResolver* Resolver)
{
if (!Attachment.IsNull())
@@ -374,17 +383,18 @@ CbPackage::AddAttachments(std::span<const CbAttachment> InAttachments)
{
ZEN_ASSERT(!Attachment.IsNull());
}
+
// Assume we have no duplicates!
Attachments.insert(Attachments.end(), InAttachments.begin(), InAttachments.end());
std::sort(Attachments.begin(), Attachments.end());
- ZEN_ASSERT_SLOW(std::unique(Attachments.begin(), Attachments.end()) == Attachments.end());
+ ZEN_ASSERT_SLOW(eastl::unique(Attachments.begin(), Attachments.end()) == Attachments.end());
}
int32_t
CbPackage::RemoveAttachment(const IoHash& Hash)
{
return gsl::narrow_cast<int32_t>(
- std::erase_if(Attachments, [&Hash](const CbAttachment& Attachment) -> bool { return Attachment.GetHash() == Hash; }));
+ erase_if(Attachments, [&Hash](const CbAttachment& Attachment) -> bool { return Attachment.GetHash() == Hash; }));
}
bool
diff --git a/src/zencore/include/zencore/compactbinarybuilder.h b/src/zencore/include/zencore/compactbinarybuilder.h
index 1c625cacc..f11717453 100644
--- a/src/zencore/include/zencore/compactbinarybuilder.h
+++ b/src/zencore/include/zencore/compactbinarybuilder.h
@@ -18,6 +18,8 @@
#include <type_traits>
#include <vector>
+#include <EASTL/fixed_vector.h>
+
#include <gsl/gsl-lite.hpp>
namespace zen {
@@ -367,6 +369,8 @@ public:
/** Private flags that are public to work with ENUM_CLASS_FLAGS. */
enum class StateFlags : uint8_t;
+ typedef eastl::fixed_vector<uint8_t, 2048> CbWriterData_t;
+
protected:
/** Reserve the specified size up front until the format is optimized. */
ZENCORE_API explicit CbWriter(int64_t InitialSize);
@@ -409,8 +413,8 @@ private:
// provided externally, such as on the stack. That format will store the offsets that require
// object or array sizes to be inserted and field types to be removed, and will perform those
// operations only when saving to a buffer.
- std::vector<uint8_t> Data;
- std::vector<WriterState> States;
+ eastl::fixed_vector<WriterState, 4> States;
+ CbWriterData_t Data;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/zencore/include/zencore/compactbinarypackage.h b/src/zencore/include/zencore/compactbinarypackage.h
index 12fcc41b7..9ec12cb0f 100644
--- a/src/zencore/include/zencore/compactbinarypackage.h
+++ b/src/zencore/include/zencore/compactbinarypackage.h
@@ -12,6 +12,8 @@
#include <span>
#include <variant>
+#include <EASTL/fixed_vector.h>
+
#ifdef GetObject
# error "windows.h pollution"
# undef GetObject
@@ -265,7 +267,10 @@ public:
}
/** Returns the attachments in this package. */
- inline std::span<const CbAttachment> GetAttachments() const { return Attachments; }
+ inline std::span<const CbAttachment> GetAttachments() const
+ {
+ return std::span<const CbAttachment>(begin(Attachments), end(Attachments));
+ }
/**
* Find an attachment by its hash.
@@ -286,6 +291,8 @@ public:
void AddAttachments(std::span<const CbAttachment> Attachments);
+ void ReserveAttachments(size_t Count);
+
/**
* Remove an attachment by hash.
*
@@ -324,9 +331,9 @@ private:
void GatherAttachments(const CbObject& Object, AttachmentResolver Resolver);
/** Attachments ordered by their hash. */
- std::vector<CbAttachment> Attachments;
- CbObject Object;
- IoHash ObjectHash;
+ eastl::fixed_vector<CbAttachment, 32> Attachments;
+ CbObject Object;
+ IoHash ObjectHash;
};
namespace legacy {
diff --git a/src/zencore/include/zencore/compositebuffer.h b/src/zencore/include/zencore/compositebuffer.h
index b435c5e74..1e1611de9 100644
--- a/src/zencore/include/zencore/compositebuffer.h
+++ b/src/zencore/include/zencore/compositebuffer.h
@@ -2,6 +2,7 @@
#pragma once
+#include <zencore/eastlutil.h>
#include <zencore/sharedbuffer.h>
#include <zencore/zencore.h>
@@ -9,6 +10,8 @@
#include <span>
#include <vector>
+#include <EASTL/fixed_vector.h>
+
namespace zen {
/**
@@ -35,7 +38,7 @@ public:
{
m_Segments.reserve((GetBufferCount(std::forward<BufferTypes>(Buffers)) + ...));
(AppendBuffers(std::forward<BufferTypes>(Buffers)), ...);
- std::erase_if(m_Segments, [](const SharedBuffer& It) { return It.IsNull(); });
+ erase_if(m_Segments, [](const SharedBuffer& It) { return It.IsNull(); });
}
}
@@ -46,7 +49,10 @@ public:
[[nodiscard]] ZENCORE_API uint64_t GetSize() const;
/** Returns the segments that the buffer is composed from. */
- [[nodiscard]] inline std::span<const SharedBuffer> GetSegments() const { return std::span<const SharedBuffer>{m_Segments}; }
+ [[nodiscard]] inline std::span<const SharedBuffer> GetSegments() const
+ {
+ return std::span<const SharedBuffer>{begin(m_Segments), end(m_Segments)};
+ }
/** Returns true if the composite buffer is not null. */
[[nodiscard]] inline explicit operator bool() const { return !IsNull(); }
@@ -120,6 +126,8 @@ public:
static const CompositeBuffer Null;
private:
+ typedef eastl::fixed_vector<SharedBuffer, 4> SharedBufferVector_t;
+
static inline size_t GetBufferCount(const CompositeBuffer& Buffer) { return Buffer.m_Segments.size(); }
inline void AppendBuffers(const CompositeBuffer& Buffer)
{
@@ -134,12 +142,25 @@ private:
inline void AppendBuffers(SharedBuffer&& Buffer) { m_Segments.push_back(std::move(Buffer)); }
inline void AppendBuffers(IoBuffer&& Buffer) { m_Segments.push_back(SharedBuffer(std::move(Buffer))); }
+ static inline size_t GetBufferCount(std::span<IoBuffer>&& Container) { return Container.size(); }
+ inline void AppendBuffers(std::span<IoBuffer>&& Container)
+ {
+ m_Segments.reserve(m_Segments.size() + Container.size());
+ for (IoBuffer& Buffer : Container)
+ {
+ m_Segments.emplace_back(SharedBuffer(std::move(Buffer)));
+ }
+ }
+
static inline size_t GetBufferCount(std::vector<SharedBuffer>&& Container) { return Container.size(); }
static inline size_t GetBufferCount(std::vector<IoBuffer>&& Container) { return Container.size(); }
inline void AppendBuffers(std::vector<SharedBuffer>&& Container)
{
m_Segments.reserve(m_Segments.size() + Container.size());
- m_Segments.insert(m_Segments.end(), std::make_move_iterator(Container.begin()), std::make_move_iterator(Container.end()));
+ for (SharedBuffer& Buffer : Container)
+ {
+ m_Segments.emplace_back(std::move(Buffer));
+ }
}
inline void AppendBuffers(std::vector<IoBuffer>&& Container)
{
@@ -150,8 +171,17 @@ private:
}
}
+ inline void AppendBuffers(SharedBufferVector_t&& Container)
+ {
+ m_Segments.reserve(m_Segments.size() + Container.size());
+ for (SharedBuffer& Buffer : Container)
+ {
+ m_Segments.emplace_back(std::move(Buffer));
+ }
+ }
+
private:
- std::vector<SharedBuffer> m_Segments;
+ SharedBufferVector_t m_Segments;
};
void compositebuffer_forcelink(); // internal
diff --git a/src/zencore/include/zencore/eastlutil.h b/src/zencore/include/zencore/eastlutil.h
new file mode 100644
index 000000000..642321dae
--- /dev/null
+++ b/src/zencore/include/zencore/eastlutil.h
@@ -0,0 +1,20 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include <algorithm>
+
+namespace zen {
+
+size_t
+erase_if(auto& _Cont, auto Predicate)
+{
+ auto _First = _Cont.begin();
+ const auto _Last = _Cont.end();
+ const auto _Old_size = _Cont.size();
+ _First = std::remove_if(_First, _Last, Predicate);
+ _Cont.erase(_First, _Last);
+ return _Old_size - _Cont.size();
+}
+
+} // namespace zen
diff --git a/src/zencore/include/zencore/memory/newdelete.h b/src/zencore/include/zencore/memory/newdelete.h
index d22c8604f..059f1d5ea 100644
--- a/src/zencore/include/zencore/memory/newdelete.h
+++ b/src/zencore/include/zencore/memory/newdelete.h
@@ -153,3 +153,29 @@ operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexce
return zen_new_aligned_nothrow(n, static_cast<size_t>(al));
}
#endif
+
+// EASTL operator new
+
+void*
+operator new[](size_t size, const char* pName, int flags, unsigned debugFlags, const char* file, int line)
+{
+ ZEN_UNUSED(pName, flags, debugFlags, file, line);
+ return zen_new(size);
+}
+
+void*
+operator new[](size_t size,
+ size_t alignment,
+ size_t alignmentOffset,
+ const char* pName,
+ int flags,
+ unsigned debugFlags,
+ const char* file,
+ int line)
+{
+ ZEN_UNUSED(alignmentOffset, pName, flags, debugFlags, file, line);
+
+ ZEN_ASSERT_SLOW(alignmentOffset == 0); // currently not supported
+
+ return zen_new_aligned(size, alignment);
+}
diff --git a/src/zencore/xmake.lua b/src/zencore/xmake.lua
index 2efa3fdb8..b8b14084c 100644
--- a/src/zencore/xmake.lua
+++ b/src/zencore/xmake.lua
@@ -55,6 +55,7 @@ target('zencore')
add_packages(
"vcpkg::doctest",
+ "vcpkg::eastl",
"vcpkg::fmt",
"vcpkg::gsl-lite",
"vcpkg::lz4",