-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce the size of Mesh, Basis & Quadrature, Direction & Size, ElementId, FixedHashMap, and combine ElementId and DirectionalId #6000
Conversation
* bits of a uint8_t, which is why we do the left shift. We cannot | ||
* have more than 16 bases to fit into the 4 bits, including the | ||
* `Uninitialized` value. The number of bits to shift is encoded in the variable | ||
* `Spectral::detail::basis_shift`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
detail
stuff should not be part of the public interface. Either make the constant non-detail or do the shift internally when using the enum instead of incorporating it into the value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how the detail is currently part of the interface. If you are adding or removing values from the enum class, then you need to know why it is being shifted and the limitations, as in, you've entered the realm of "details". If you are just using it, you shouldn't be casting an enum class anyway. Should I make this a \warning
or preface it with If you are changing the values in this
or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You use it in src/IO/H5/VolumeData.cpp
.
friend bool operator==(const Mesh<LocalDim>& lhs, const Mesh<LocalDim>& rhs); | ||
|
||
// - 8 bits per extent = 3 * 8 = 24 bits = 3 bytes | ||
// This limits us to 128 extent per direction. Since FD is 2x DG, this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where does 128 come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, probably a typo when computing 2^8. I think the limitation is 255 in practice on FD, which would be a limit of 127 on DG. Does that clarify? (If so, I'll update the comments)
// This limits us to 128 extent per direction. Since FD is 2x DG, this | ||
// means at most 64 DG points, which is should be fine. | ||
// - We encode the basis & quadrature as two sets of 4 bits in a uint8_t. | ||
std::array<uint8_t, 6> bit_field_{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this would be easier to read if you had two arrays of size 3 instead of one array of size 6 with the first and second halves interpreted differently.
std::array<Spectral::Basis, Dim> bases_{}; | ||
std::array<Spectral::Quadrature, Dim> quadratures_{}; | ||
static Spectral::Basis extract_basis(uint8_t bits); | ||
static Spectral::Quadrature extract_quadrature(uint8_t bits); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[optional] Bit of a weird asymmetry in that the combining function is in an anonymous namespace but the extracting functions are private statics. I'd make them them all anonymous.
@@ -95,6 +95,7 @@ void test_explicit_choices_per_dimension() { | |||
test_extents_basis_and_quadrature(mesh1d, {{2}}, | |||
{{Spectral::Basis::Legendre}}, | |||
{{Spectral::Quadrature::GaussLobatto}}); | |||
return; | |||
CHECK(mesh1d.slice_away(0) == Mesh<0>{}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix something.
src/Domain/Structure/Direction.cpp
Outdated
side_ = side; | ||
template <size_t VolumeDim> | ||
uint8_t Direction<VolumeDim>::self_bits() { | ||
return static_cast<uint8_t>(Axis::Xi) bitor static_cast<uint8_t>(Side::Self); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[optional] return self().bits();
to reduce duplication. (Or even get rid of this function entirely.)
src/Domain/Structure/ElementId.cpp
Outdated
: block_id_(element_id.block_id_), | ||
grid_index_(element_id.grid_index_), | ||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) | ||
direction_(*reinterpret_cast<const uint8_t*>(&direction)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
direction_(direction.bits())
Reduces size of serialized objects.
Rebased and pushed fixups. Thanks for the reviews! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
streaming in the ASSERT is not working on the failing build...
otherwise you have my permission to squash once you have the okay from @wthrowe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squash.
p | bit_field_; | ||
p | extents_; | ||
p | quadrature_and_basis_; | ||
// p | bit_field_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove.
@@ -274,7 +276,9 @@ bool is_isotropic(const Mesh<Dim>& mesh) { | |||
|
|||
template <size_t Dim> | |||
bool operator==(const Mesh<Dim>& lhs, const Mesh<Dim>& rhs) { | |||
return lhs.bit_field_ == rhs.bit_field_; | |||
// return lhs.bit_field_ == rhs.bit_field_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove.
This reduces the size of Mesh from 48 bytes to 6 bytes. We store the mesh quite a few places and it ends up being around 1kB per element at 48 bytes. Also moves various functions that needed editing into the cpp file.
This needs to be one commit because we version these tiny classes.
Okay, done! I verified that the test failure is fixed locally so 🤞 |
Proposed changes
After looking at memory consumption, @kidder, @wthrowe and I were surprised how much these small classes ended up using. This is because we have a lot of them stored per element. Using smaller integer types greatly reduces the memory usage, and then some bit twiddling is done internally in a few classes to further reduce memory usage. This should also help by reducing memory traffic (being able to load an entire Mesh in 1 load instead of 6, etc.). The bit twiddling is just simple bitmasks so nothing too crazy.
One thing I found quite inconvenient and a bit silly is that we version tiny classes like
Direction
. We should instead be versioning the Domain during serialization, not all these small classes. In some cases we used more bytes during serialization for the version than the actual data. That seems unnecessary. In cases where I could, I compressed the version info into unused bits by other parts of the class. This helps, but still seems silly.Upgrade instructions
Code review checklist
make doc
to generate the documentation locally intoBUILD_DIR/docs/html
.Then open
index.html
.code review guide.
bugfix
ornew feature
if appropriate.Further comments