Skip to content

Commit 90cfea1

Browse files
committed
[ntuple] use TClass alignment info where possible
1 parent fbb3759 commit 90cfea1

12 files changed

Lines changed: 139 additions & 35 deletions

tree/ntuple/inc/ROOT/RField.hxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ private:
164164
TClass *fClass;
165165
/// Additional information kept for each entry in `fSubfields`
166166
std::vector<RSubfieldInfo> fSubfieldsInfo;
167-
std::size_t fMaxAlignment = 1;
168167

169168
/// The staging area stores inputs to I/O rules according to the offsets given by the streamer info of
170169
/// "TypeName@@Version". The area is allocated depending on I/O rules resp. the source members of the I/O rules.
@@ -219,8 +218,8 @@ public:
219218
~RClassField() override;
220219

221220
std::vector<RValue> SplitValue(const RValue &value) const final;
222-
size_t GetValueSize() const final;
223-
size_t GetAlignment() const final { return fMaxAlignment; }
221+
std::size_t GetValueSize() const final;
222+
std::size_t GetAlignment() const final;
224223
std::uint32_t GetTypeVersion() const final;
225224
std::uint32_t GetTypeChecksum() const final;
226225
/// For polymorphic classes (that declare or inherit at least one virtual method), return the expected dynamic type

tree/ntuple/inc/ROOT/RField/RFieldProxiedCollection.hxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ public:
175175
~RProxiedCollectionField() override = default;
176176

177177
std::vector<RValue> SplitValue(const RValue &value) const final;
178-
size_t GetValueSize() const final { return fProxy->Sizeof(); }
179-
size_t GetAlignment() const final { return alignof(std::max_align_t); }
178+
std::size_t GetValueSize() const final;
179+
std::size_t GetAlignment() const final;
180180
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
181181
};
182182

tree/ntuple/inc/ROOT/RField/RFieldSTLMisc.hxx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ public:
263263
~ROptionalField() override = default;
264264

265265
std::vector<RValue> SplitValue(const RValue &value) const final;
266-
size_t GetValueSize() const final;
267-
size_t GetAlignment() const final;
266+
std::size_t GetValueSize() const final;
267+
std::size_t GetAlignment() const final;
268268
};
269269

270270
template <typename ItemT>
@@ -312,8 +312,8 @@ public:
312312
~RUniquePtrField() override = default;
313313

314314
std::vector<RValue> SplitValue(const RValue &value) const final;
315-
size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
316-
size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
315+
std::size_t GetValueSize() const final { return sizeof(std::unique_ptr<char>); }
316+
std::size_t GetAlignment() const final { return alignof(std::unique_ptr<char>); }
317317
};
318318

319319
template <typename ItemT>
@@ -362,8 +362,8 @@ public:
362362
RField &operator=(RField &&other) = default;
363363
~RField() final = default;
364364

365-
size_t GetValueSize() const final { return sizeof(std::string); }
366-
size_t GetAlignment() const final { return std::alignment_of<std::string>(); }
365+
std::size_t GetValueSize() const final { return sizeof(std::string); }
366+
std::size_t GetAlignment() const final { return alignof(std::string); }
367367
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
368368
};
369369

@@ -435,8 +435,8 @@ public:
435435
RVariantField &operator=(RVariantField &&other) = default;
436436
~RVariantField() override = default;
437437

438-
size_t GetValueSize() const final;
439-
size_t GetAlignment() const final;
438+
std::size_t GetValueSize() const final;
439+
std::size_t GetAlignment() const final;
440440
};
441441

442442
template <typename... ItemTs>

tree/ntuple/inc/ROOT/RField/RFieldSequenceContainer.hxx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ public:
265265
CreateUntyped(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField);
266266

267267
std::vector<RValue> SplitValue(const RValue &value) const final;
268-
size_t GetValueSize() const final { return sizeof(std::vector<char>); }
269-
size_t GetAlignment() const final { return std::alignment_of<std::vector<char>>(); }
268+
std::size_t GetValueSize() const final;
269+
std::size_t GetAlignment() const final;
270270
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
271271
};
272272

@@ -319,8 +319,8 @@ public:
319319

320320
std::vector<RValue> SplitValue(const RValue &value) const final;
321321

322-
size_t GetValueSize() const final { return sizeof(std::vector<bool>); }
323-
size_t GetAlignment() const final { return std::alignment_of<std::vector<bool>>(); }
322+
std::size_t GetValueSize() const final { return sizeof(std::vector<bool>); }
323+
std::size_t GetAlignment() const final { return alignof(std::vector<bool>); }
324324
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;
325325
};
326326

@@ -414,8 +414,8 @@ public:
414414
RArrayAsVectorField &operator=(RArrayAsVectorField &&other) = default;
415415
~RArrayAsVectorField() final = default;
416416

417-
size_t GetValueSize() const final { return sizeof(std::vector<char>); }
418-
size_t GetAlignment() const final { return std::alignment_of<std::vector<char>>(); }
417+
std::size_t GetValueSize() const final;
418+
std::size_t GetAlignment() const final;
419419

420420
std::vector<RFieldBase::RValue> SplitValue(const RFieldBase::RValue &value) const final;
421421
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final;

tree/ntuple/inc/ROOT/RField/RFieldSoA.hxx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ class RSoAField : public RFieldBase {
6969
std::vector<std::size_t> fSoAMemberOffsets;
7070
///< A deleter returned by each record member's GetDeleter()
7171
std::vector<std::unique_ptr<RDeleter>> fRecordMemberDeleters;
72-
std::size_t fMaxAlignment = 1;
7372
ROOT::Internal::RColumnIndex fNWritten;
7473

7574
/// For reading and writing, the RVecs of the SoA class do not have a dedicated field. The in-memory RVecs of the
@@ -105,7 +104,7 @@ public:
105104

106105
std::vector<RValue> SplitValue(const RValue &value) const final;
107106
size_t GetValueSize() const final;
108-
size_t GetAlignment() const final { return fMaxAlignment; }
107+
size_t GetAlignment() const final;
109108
std::uint32_t GetTypeVersion() const final;
110109
std::uint32_t GetTypeChecksum() const final;
111110
/// For polymorphic classes (that declare or inherit at least one virtual method), return the expected dynamic type

tree/ntuple/inc/ROOT/RFieldBase.hxx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ protected:
555555
const ROOT::RNTupleDescriptor *desc, ROOT::DescriptorId_t fieldId);
556556

557557
public:
558+
/// Maximum supported alignment for field types, i.e. maximum returned by GetAlignment()
559+
static constexpr std::size_t kMaxAlignment = 4096;
560+
558561
template <bool IsConstT>
559562
class RSchemaIteratorTemplate;
560563
using RSchemaIterator = RSchemaIteratorTemplate<false>;
@@ -623,10 +626,9 @@ public:
623626
/// correct `std::variant` or all the elements of a collection. The default implementation assumes no subvalues
624627
/// and returns an empty vector.
625628
virtual std::vector<RValue> SplitValue(const RValue &value) const;
626-
/// The number of bytes taken by a value of the appropriate type
629+
/// What sizeof(T) for this type returns
627630
virtual size_t GetValueSize() const = 0;
628-
/// As a rule of thumb, the alignment is equal to the size of the type. There are, however, various exceptions
629-
/// to this rule depending on OS and CPU architecture. So enforce the alignment to be explicitly spelled out.
631+
/// What alignof(T) for this type returns
630632
virtual size_t GetAlignment() const = 0;
631633
std::uint32_t GetTraits() const { return fTraits; }
632634
bool HasReadCallbacks() const { return !fReadCallbacks.empty(); }

tree/ntuple/src/RFieldMeta.cxx

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// - RField<TObject>
1515
// - RVariantField
1616

17+
#include <ROOT/BitUtils.hxx>
1718
#include <ROOT/RField.hxx>
1819
#include <ROOT/RFieldBase.hxx>
1920
#include <ROOT/RFieldUtils.hxx>
@@ -116,6 +117,12 @@ TEnum *EnsureValidEnum(std::string_view enumName)
116117
return e;
117118
}
118119

120+
void EnsureValidAlignment(std::size_t align)
121+
{
122+
if (align == 0 || align > ROOT::RFieldBase::kMaxAlignment || !ROOT::Internal::IsPowerOfTwo(align))
123+
throw ROOT::RException(R__FAIL(std::string("invalid alignment: ") + std::to_string(align)));
124+
}
125+
119126
/// Create a comma-separated list of type names from the given fields. Uses either the real type names or the
120127
/// type aliases (if there are any, otherwise the actual type name). Used to construct template argument lists
121128
/// for templated types such as std::pair<...>, std::tuple<...>, std::variant<...>.
@@ -186,8 +193,7 @@ std::string BuildMapTypeName(ROOT::RMapField::EMapType mapType, const ROOT::RFie
186193
ROOT::RClassField::RClassField(std::string_view fieldName, const RClassField &source)
187194
: ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kRecord, false /* isSimple */),
188195
fClass(source.fClass),
189-
fSubfieldsInfo(source.fSubfieldsInfo),
190-
fMaxAlignment(source.fMaxAlignment)
196+
fSubfieldsInfo(source.fSubfieldsInfo)
191197
{
192198
for (const auto &f : source.GetConstSubfields()) {
193199
RFieldBase::Attach(f->Clone(f->GetFieldName()));
@@ -280,7 +286,6 @@ ROOT::RClassField::~RClassField()
280286

281287
void ROOT::RClassField::Attach(std::unique_ptr<RFieldBase> child, RSubfieldInfo info)
282288
{
283-
fMaxAlignment = std::max(fMaxAlignment, child->GetAlignment());
284289
fSubfieldsInfo.push_back(info);
285290
RFieldBase::Attach(std::move(child));
286291
}
@@ -622,11 +627,18 @@ std::vector<ROOT::RFieldBase::RValue> ROOT::RClassField::SplitValue(const RValue
622627
return result;
623628
}
624629

625-
size_t ROOT::RClassField::GetValueSize() const
630+
std::size_t ROOT::RClassField::GetValueSize() const
626631
{
627632
return fClass->GetClassSize();
628633
}
629634

635+
std::size_t ROOT::RClassField::GetAlignment() const
636+
{
637+
const auto align = fClass->GetClassAlignment();
638+
EnsureValidAlignment(align);
639+
return align;
640+
}
641+
630642
std::uint32_t ROOT::RClassField::GetTypeVersion() const
631643
{
632644
return fClass->GetClassVersion();
@@ -656,8 +668,7 @@ void ROOT::RClassField::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) cons
656668
ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, const RSoAField &source)
657669
: ROOT::RFieldBase(fieldName, source.GetTypeName(), ROOT::ENTupleStructure::kCollection, false /* isSimple */),
658670
fSoAClass(source.fSoAClass),
659-
fSoAMemberOffsets(source.fSoAMemberOffsets),
660-
fMaxAlignment(source.fMaxAlignment)
671+
fSoAMemberOffsets(source.fSoAMemberOffsets)
661672
{
662673
fTraits = source.GetTraits();
663674
Attach(source.fSubfields[0]->Clone(source.fSubfields[0]->GetFieldName()));
@@ -763,8 +774,6 @@ ROOT::Experimental::RSoAField::RSoAField(std::string_view fieldName, TClass *clS
763774
leftType + " vs. " + rightType + ")"));
764775
}
765776

766-
fMaxAlignment = std::max(fMaxAlignment, vecField->GetAlignment());
767-
768777
assert(itr->second < fSoAMemberOffsets.size());
769778
fSoAMemberOffsets[itr->second] = dataMember->GetOffset();
770779
nMembers++;
@@ -910,7 +919,7 @@ std::vector<ROOT::RFieldBase::RValue> ROOT::Experimental::RSoAField::SplitValue(
910919
return values;
911920
}
912921

913-
size_t ROOT::Experimental::RSoAField::GetValueSize() const
922+
std::size_t ROOT::Experimental::RSoAField::GetValueSize() const
914923
{
915924
return fSoAClass->GetClassSize();
916925
}
@@ -925,6 +934,13 @@ std::uint32_t ROOT::Experimental::RSoAField::GetTypeChecksum() const
925934
return fSoAClass->GetCheckSum();
926935
}
927936

937+
std::size_t ROOT::Experimental::RSoAField::GetAlignment() const
938+
{
939+
const auto align = fSoAClass->GetClassAlignment();
940+
EnsureValidAlignment(align);
941+
return align;
942+
}
943+
928944
const std::type_info *ROOT::Experimental::RSoAField::GetPolymorphicTypeInfo() const
929945
{
930946
// TODO(jblomer): factor out
@@ -1250,6 +1266,18 @@ std::vector<ROOT::RFieldBase::RValue> ROOT::RProxiedCollectionField::SplitValue(
12501266
return result;
12511267
}
12521268

1269+
std::size_t ROOT::RProxiedCollectionField::GetValueSize() const
1270+
{
1271+
return fProxy->Sizeof();
1272+
}
1273+
1274+
std::size_t ROOT::RProxiedCollectionField::GetAlignment() const
1275+
{
1276+
const auto align = fProxy->GetCollectionClass()->GetClassAlignment();
1277+
EnsureValidAlignment(align);
1278+
return align;
1279+
}
1280+
12531281
void ROOT::RProxiedCollectionField::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
12541282
{
12551283
visitor.VisitProxiedCollectionField(*this);
@@ -1457,7 +1485,9 @@ ROOT::RExtraTypeInfoDescriptor ROOT::RStreamerField::GetExtraTypeInfo() const
14571485

14581486
std::size_t ROOT::RStreamerField::GetAlignment() const
14591487
{
1460-
return std::min(alignof(std::max_align_t), GetValueSize()); // TODO(jblomer): fix me
1488+
const auto align = fClass->GetClassAlignment();
1489+
EnsureValidAlignment(align);
1490+
return align;
14611491
}
14621492

14631493
std::size_t ROOT::RStreamerField::GetValueSize() const

tree/ntuple/src/RFieldSequenceContainer.cxx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/// \author Jonas Hahnfeld <jonas.hahnfeld@cern.ch>
33
/// \date 2024-11-19
44

5+
#include <ROOT/BitUtils.hxx>
56
#include <ROOT/RField.hxx>
67
#include <ROOT/RFieldBase.hxx>
78
#include <ROOT/RFieldVisitor.hxx>
@@ -29,6 +30,16 @@ std::vector<ROOT::RFieldBase::RValue> SplitVector(std::shared_ptr<void> valuePtr
2930
return result;
3031
}
3132

33+
std::size_t GetSizeOfVector()
34+
{
35+
return sizeof(std::vector<char>);
36+
}
37+
38+
std::size_t GetAlignOfVector()
39+
{
40+
return alignof(std::vector<char>);
41+
}
42+
3243
} // anonymous namespace
3344

3445
ROOT::RArrayField::RArrayField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField,
@@ -647,6 +658,16 @@ std::vector<ROOT::RFieldBase::RValue> ROOT::RVectorField::SplitValue(const RValu
647658
return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
648659
}
649660

661+
std::size_t ROOT::RVectorField::GetValueSize() const
662+
{
663+
return GetSizeOfVector();
664+
}
665+
666+
std::size_t ROOT::RVectorField::GetAlignment() const
667+
{
668+
return GetAlignOfVector();
669+
}
670+
650671
void ROOT::RVectorField::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
651672
{
652673
visitor.VisitVectorField(*this);
@@ -973,6 +994,16 @@ std::vector<ROOT::RFieldBase::RValue> ROOT::RArrayAsVectorField::SplitValue(cons
973994
return SplitVector(value.GetPtr<void>(), *fSubfields[0]);
974995
}
975996

997+
std::size_t ROOT::RArrayAsVectorField::GetValueSize() const
998+
{
999+
return GetSizeOfVector();
1000+
}
1001+
1002+
std::size_t ROOT::RArrayAsVectorField::GetAlignment() const
1003+
{
1004+
return GetAlignOfVector();
1005+
}
1006+
9761007
void ROOT::RArrayAsVectorField::AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const
9771008
{
9781009
visitor.VisitArrayAsVectorField(*this);

tree/ntuple/test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(CustomStruct
1111
HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/CustomStruct.hxx
1212
SOURCES CustomStruct.cxx
1313
LINKDEF CustomStructLinkDef.h
14-
DEPENDENCIES RIO)
14+
DEPENDENCIES RIO ROOTVecOps)
1515
configure_file(CustomStruct.hxx . COPYONLY)
1616
if(MSVC AND NOT CMAKE_GENERATOR MATCHES Ninja)
1717
add_custom_command(TARGET CustomStruct POST_BUILD

tree/ntuple/test/CustomStruct.hxx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
#ifndef ROOT_RNTuple_Test_CustomStruct
22
#define ROOT_RNTuple_Test_CustomStruct
33

4+
#include <ROOT/RVec.hxx>
5+
46
#include <RtypesCore.h> // for Double32_t
57
#include <TObject.h>
68
#include <TRootIOCtor.h>
79
#include <TVirtualCollectionProxy.h>
810

11+
#include <array>
912
#include <chrono>
1013
#include <stdexcept>
1114
#include <cstddef>
@@ -478,4 +481,20 @@ struct MemberWithCustomStreamer {
478481
ClassDefNV(MemberWithCustomStreamer, 2);
479482
};
480483

484+
struct AlignmentDeterminedByTransientMember {
485+
short int fA;
486+
float fTransient; ///<!
487+
};
488+
489+
struct alignas(8) AlignedAs {};
490+
491+
struct alignas(64) OverAligned {
492+
std::uint32_t fA;
493+
};
494+
495+
struct AlignmentEnvelope {
496+
ROOT::RVec<OverAligned> fVec;
497+
std::array<OverAligned, 2> fArr;
498+
};
499+
481500
#endif

0 commit comments

Comments
 (0)