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:
Dion Moult
2026-09-11 16:46:58 +10:00
parent 64805b409f
commit d0ac888819
3 changed files with 35 additions and 28 deletions
+1 -1
View File
@@ -3599,7 +3599,7 @@ instance_data::instance_data(const instance_data& data)
attribute_value instance_data::get_attribute_value(size_t index) const
{
if (storage_) {
return attribute_value(storage_, (uint8_t)index);
return attribute_value(&*storage_, (uint8_t)index);
} else {
auto* const storage = std::visit([](auto& m) -> ifcopenshell::impl::rocks_db_file_storage* {
using U = std::decay_t<decltype(m)>;