mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 00:00:56 +00:00
ifcparse: two heap allocations per instance instead of four
Each instance was four separate allocations: the instance_data record, the attribute array object it pointed at, that array's index bytes, and its slot storage. A 58 MB model made 10.4 million mallocs to load 918k instances, and massif attributed 99 MB of its 450 MB peak to malloc bookkeeping alone. variant_array now allocates the size byte, the per-slot type indices and the slots as one block, and instance_data holds the array in a std::optional instead of behind a pointer (an empty optional keeps the meaning the null pointer had: attribute storage constructed on the fly from the RocksDB backend). No ownership or lifetime changes; the same object owns the same data. Parse, C++ file constructor, on top of the previous commits: TXG 58 MB 0.96 -> 0.94 s steady 310 -> 262 MB peak 383 -> 335 MB 210_King 148 MB 2.74 -> 2.63 s steady 758 -> 630 MB peak 948 -> 820 MB OKgate22 232 MB 3.70 -> 3.61 s steady 1165 -> 971 MB peak 1447 -> 1252 MB mallocs while loading TXG: 10.39M -> 7.56M. This commit was written by an AI coding tool and has not been verified by a human. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013wcN7XquTfUi4vsKQ4KchL
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
@@ -509,8 +510,8 @@ class IFC_PARSE_API instance_data {
|
||||
void populate_derived_();
|
||||
|
||||
public:
|
||||
// Since rocks_db_attribute_storage has no members this is not a variant<in_memory, rocks> but in_memory*, where nullptr means a rocks_db_attribute_storage is constructed on the fly given the context from instance data.
|
||||
in_memory_attribute_storage* storage_;
|
||||
// Since rocks_db_attribute_storage has no members this is not a variant<in_memory, rocks> but an optional in_memory storage, where an empty optional means a rocks_db_attribute_storage is constructed on the fly given the context from instance data.
|
||||
std::optional<in_memory_attribute_storage> storage_;
|
||||
|
||||
const ifcopenshell::declaration* declaration() const {
|
||||
return declaration_;
|
||||
@@ -529,13 +530,13 @@ class IFC_PARSE_API instance_data {
|
||||
}
|
||||
|
||||
instance_data(ifcopenshell::file* file, const ifcopenshell::declaration* declaration, uint32_t id, in_memory_attribute_storage&& storage)
|
||||
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(new in_memory_attribute_storage(std::move(storage)))
|
||||
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(std::move(storage))
|
||||
{
|
||||
populate_derived_();
|
||||
}
|
||||
|
||||
instance_data(ifcopenshell::file* file, const ifcopenshell::declaration* declaration, uint32_t id, rocks_db_attribute_storage&& storage)
|
||||
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(nullptr)
|
||||
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(std::nullopt)
|
||||
{
|
||||
static_cast<void>(storage);
|
||||
populate_derived_();
|
||||
@@ -544,7 +545,7 @@ class IFC_PARSE_API instance_data {
|
||||
/*
|
||||
// now that there are referenced as shared_ptr there is no move constructor anymore
|
||||
instance_data(instance_data&& other) noexcept
|
||||
: file_(other.file_), id_(other.id_), declaration_(other.declaration_), storage_(std::exchange(other.storage_, nullptr))
|
||||
: file_(other.file_), id_(other.id_), declaration_(other.declaration_), storage_(std::move(other.storage_))
|
||||
{}
|
||||
*/
|
||||
|
||||
@@ -558,15 +559,15 @@ class IFC_PARSE_API instance_data {
|
||||
// same
|
||||
instance_data& operator=(instance_data&& other) noexcept {
|
||||
if (this != &other) {
|
||||
delete storage_;
|
||||
storage_ = std::exchange(other.storage_, nullptr);
|
||||
storage_ = std::move(other.storage_);
|
||||
other.storage_.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
*/
|
||||
|
||||
~instance_data() {
|
||||
delete storage_;
|
||||
storage_.reset();
|
||||
}
|
||||
|
||||
attribute_value get_attribute_value(size_t attribute_index) const;
|
||||
|
||||
Reference in New Issue
Block a user