[ntuple] Fixes for alignment#22312
Conversation
bb61c3d to
694bd02
Compare
27ddc85 to
ba94832
Compare
Test Results 22 files 22 suites 3d 9h 39m 40s ⏱️ For more details on these failures, see this check. Results for commit aa8c36c. ♻️ This comment has been updated with latest results. |
|
|
||
| void ROOT::RFieldBase::EnsureValidAlignment(std::size_t alignment) | ||
| { | ||
| if (alignment == 0 || alignment > ROOT::RFieldBase::kMaxAlignment || !ROOT::Internal::IsPowerOfTwo(alignment)) |
There was a problem hiding this comment.
This is similar (but different) to ROOT::Internal::IsValidAlignment.
| if (alignment == 0 || alignment > ROOT::RFieldBase::kMaxAlignment || !ROOT::Internal::IsPowerOfTwo(alignment)) | |
| if (!ROOT::Internal::IsValidAlignment(alignment) || alignment > ROOT::RFieldBase::kMaxAlignment) |
At least in the main I/O part the limitation to 4096 is only for std::vector because they can be handled without dictionary (but then we need to explicitly handle the alignment of their content.
Is RNTuple more restrictive (i.e. calling an generically provided call to new for various alignment?)
There was a problem hiding this comment.
Actually it isn't. Assuming that the std::vector layout doesn't change depending on the alignment of its item type, RNTuple has no further maximum alignment restrictions of its own. At the moment, I use the maximum alignment to verify that the std::vector alignment is independent.
In general, I thought that it makes sense to have either no size limit or one size limit for all types.
There was a problem hiding this comment.
I can see how it might be simpler for user but I find it confusing for developer as the vector limitation is very specific, localized and 'easy' to increase, if a user report reaching the limit for another containers we might (at least temporarily) be confused of where to lift the limit for that other containers.
There was a problem hiding this comment.
Makes sense. I changed the code such that the limitation is only active for the vector field.
hahnjo
left a comment
There was a problem hiding this comment.
The code changes look good overall; quickly looking at the failures, it appears that macOS and Windows are complaining about the missing import of <array>. Not sure if that solves all issues...
hahnjo
left a comment
There was a problem hiding this comment.
As discussed offline, this is missing the part of aligning the dynamic array in std::vector<T> (relatively easy to do) and RVec<T> (harder because it currently uses malloc and free). In the worst case, we discussed throwing in case we have alignment larger than std::max_align_t
787669e to
2c2dc4a
Compare
| void ROOT::RFieldBase::EnsureValidAlignment(std::size_t alignment) | ||
| { | ||
| if (!Internal::IsValidAlignment(alignment) || alignment > ROOT::RFieldBase::kMaxAlignment) | ||
| throw ROOT::RException(R__FAIL(std::string("invalid alignment: ") + std::to_string(alignment))); |
There was a problem hiding this comment.
I think it would be more helpful for the user to be more specific about the error message.
| throw ROOT::RException(R__FAIL(std::string("invalid alignment: ") + std::to_string(alignment))); | |
| if (!Internal::IsValidAlignment(alignment)) | |
| throw ROOT::RException(R__FAIL(std::string("invalid alignment: ") + std::to_string(alignment))); | |
| // If user report alignment is excess of our support 'all' we need to do is extend the cases supported | |
| // for vector (see RFieldSequenceContainer.cxx's ConstructVector and TEmulatedCollectionProxy.h) | |
| // and then increase kMaxAlignment. | |
| if (alignment > ROOT::RFieldBase::kMaxAlignment) | |
| throw ROOT::RException(R__FAIL(std::string("Unsupported alignment: ") + std::to_string(alignment))); |
There was a problem hiding this comment.
Done as part of the switch statements in RVectorField.
2c2dc4a to
aa8c36c
Compare
| if (alignOfValue <= sizeof(std::max_align_t)) { | ||
| new (where) std::vector<char>(); | ||
| } else { |
There was a problem hiding this comment.
What is the advantage of special casing the alignment 1, 2, 4 and 8 (i.e. the effective role of this if statement)?
| case 1024: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<1024>> *>(objPtr)); break; | ||
| case 2048: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<2048>> *>(objPtr)); break; | ||
| case 4096: std::destroy_at(static_cast<std::vector<Internal::RAlignedStorage<4096>> *>(objPtr)); break; | ||
| default: R__ASSERT(false); |
There was a problem hiding this comment.
What is the advantage of having here an R__ASSERT while in other similar case we use throw?
Use the new
TClassalignment information where applicable. This fixesAdditionally, use the
newanddeleteoperators with alignment info. This ensures correct memory allocation for over-aligned types.Fixes #16765