-
Notifications
You must be signed in to change notification settings - Fork 25
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
minimize save/restore allocations #909
base: master
Are you sure you want to change the base?
Conversation
📝 Walkthrough📝 WalkthroughWalkthroughThe pull request introduces several modifications across multiple files, primarily focusing on enhancing the Changes
Possibly related PRs
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
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.
Actionable comments posted: 6
🧹 Outside diff range and nitpick comments (9)
src/core/def.hpp (3)
Line range hint
28-36
: Consider adding compile-time checks and documentationThe
isUsable
function is well-implemented using modern C++ features. However, consider the following improvements:
Add a compile-time check to ensure non-pointer types have an
isUsable()
method. This can prevent cryptic compile errors if a type withoutisUsable()
is passed.Add documentation explaining the function's purpose, usage, and requirements for the argument types.
Here's a suggested implementation with compile-time checks and documentation:
/** * @brief Checks if all provided arguments are usable. * * For pointer types, checks if the pointer is not null. * For non-pointer types, calls the isUsable() method. * * @tparam Args Variadic template parameter pack * @param args Arguments to check * @return true if all arguments are usable, false otherwise */ NO_DISCARD bool isUsable(auto const&... args) { auto check = [](auto const& arg) { if constexpr (std::is_pointer_v<std::decay_t<decltype(arg)>>) return arg != nullptr; else { static_assert(requires { arg.isUsable(); }, "Non-pointer types must have an isUsable() method"); return arg.isUsable(); } }; return (check(args) && ...); }This implementation adds a
static_assert
to ensure non-pointer types have anisUsable()
method, and includes documentation for better understanding and maintainability.
Line range hint
39-47
: ImproveisSettable
implementation and consider refactoringThe
isSettable
function is similar toisUsable
, but with some key differences. Consider the following improvements:
- Add a compile-time check for the
isSettable()
method on non-pointer types.- Add documentation explaining the function's purpose, usage, and the difference in pointer behavior compared to
isUsable
.- Consider refactoring to reduce code duplication between
isUsable
andisSettable
.Here's a suggested implementation with improvements:
/** * @brief Checks if all provided arguments are settable. * * For pointer types, checks if the pointer is null. * For non-pointer types, calls the isSettable() method. * * @note This function considers null pointers as settable, * which is the opposite of isUsable(). * * @tparam Args Variadic template parameter pack * @param args Arguments to check * @return true if all arguments are settable, false otherwise */ NO_DISCARD bool isSettable(auto const&... args) { auto check = [](auto const& arg) { if constexpr (std::is_pointer_v<std::decay_t<decltype(arg)>>) return arg == nullptr; else { static_assert(requires { arg.isSettable(); }, "Non-pointer types must have an isSettable() method"); return arg.isSettable(); } }; return (check(args) && ...); }To reduce code duplication, consider creating a helper template function:
template<bool (CheckFunc)(auto const&)> NO_DISCARD bool checkAll(auto const&... args) { return (CheckFunc(args) && ...); } NO_DISCARD bool isUsable(auto const&... args) { return checkAll<[](auto const& arg) { if constexpr (std::is_pointer_v<std::decay_t<decltype(arg)>>) return arg != nullptr; else { static_assert(requires { arg.isUsable(); }, "Non-pointer types must have an isUsable() method"); return arg.isUsable(); } }>(args...); } NO_DISCARD bool isSettable(auto const&... args) { return checkAll<[](auto const& arg) { if constexpr (std::is_pointer_v<std::decay_t<decltype(arg)>>) return arg == nullptr; else { static_assert(requires { arg.isSettable(); }, "Non-pointer types must have an isSettable() method"); return arg.isSettable(); } }>(args...); }This refactoring reduces code duplication while maintaining the specific logic for each function.
Line range hint
1-48
: Approve overall structure with minor suggestionThe overall structure of the file is well-organized, with macro definitions at the top and function definitions within the
PHARE::core
namespace. The use of macros for conditional compilation and string manipulation is appropriate for a C++ project.For consistency, consider adding a blank line before the closing brace of the namespace (line 47). This improves readability by clearly separating the namespace content from its closing brace.
src/core/data/particles/particle_array.hpp (4)
44-44
: LGTM with a minor suggestion.The updated constructor with default parameters enhances flexibility in object creation. However, consider adding a comment explaining the implications of using default values, especially for the
box
parameter, to prevent unintended usage.
76-77
: LGTM with a documentation suggestion.The new
data()
functions provide useful direct access to the underlying particle data. However, to ensure proper usage:
- Add documentation comments explaining the purpose and any potential risks of using these functions.
- Consider marking these functions with
[[nodiscard]]
instead ofNO_DISCARD
for better standard compliance.Example:
[[nodiscard]] auto data() const { return particles_.data(); } [[nodiscard]] auto data() { return particles_.data(); }
234-234
: LGTM with documentation and encapsulation considerations.The
map()
function provides access to the internalcellMap_
, which can be useful for certain operations. However:
- Add a documentation comment explaining the purpose and usage of this function.
- Consider if exposing the internal
cellMap_
directly is necessary, or if specific operations on the map could be provided as member functions instead, to maintain better encapsulation.Example documentation:
/** * @brief Get a const reference to the internal cell map. * @return Const reference to the CellMap_t object. * @note Use with caution as it exposes internal implementation details. */ auto& map() const { return cellMap_; }
247-254
: LGTM with suggestions for error checking and documentation.The new
replace_from
overload provides an efficient way to replace particle data from external sources. However, consider the following improvements:
- Add input validation to ensure
size
is not zero andparticles
is not null.- Consider adding a debug assertion to check if the provided
map
size matches thesize
parameter.- Add a documentation comment explaining the purpose, parameters, and any assumptions about the input data.
Example improvements:
/** * @brief Replace the particle array contents with provided data. * @param particles Pointer to an array of Particle_t objects. * @param size Number of particles in the array. * @param map CellMap_t object corresponding to the particle data. * @return Reference to this ParticleArray object. * @throw std::invalid_argument if particles is null or size is 0. */ auto& replace_from(Particle_t const* particles, std::size_t size, CellMap_t const& map) { if (particles == nullptr || size == 0) throw std::invalid_argument("Invalid input: null pointer or zero size"); assert(size == map.size() && "Size mismatch between particle data and cell map"); this->resize(size); this->cellMap_ = map; this->box_ = map.box(); std::copy(particles, particles + size, particles_.data()); return *this; }src/core/vector.hpp (2)
47-47
: Use a more descriptive variable name for_c
The variable
_c
serves as a counter for tracking consecutive low-usage instances but is not descriptively named.Line 47:
std::uint16_t _c = 0;Consider renaming
_c
to something more descriptive, such aslowUsageCounter
orconsecutiveLowUsageCount
, to enhance code readability and maintainability.
15-34
: Add comments to clarify resizing logic for better maintainabilityThe logic within the
get
function is complex and may not be immediately clear to other developers.Lines 15-34:
template<bool copy_old = copy_old_> auto& get(std::size_t const& s) { // Resizing logic... }Adding comments that explain:
- The purpose of
_c
,percentile
,period
, andrealloc_to
.- How the resizing mechanism works.
- The conditions under which the vector is resized.
This will greatly aid in understanding and maintaining the code.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (5)
- src/amr/solvers/solver_ppc.hpp (6 hunks)
- src/core/data/particles/particle_array.hpp (4 hunks)
- src/core/def.hpp (1 hunks)
- src/core/utilities/cellmap.hpp (1 hunks)
- src/core/vector.hpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
src/amr/solvers/solver_ppc.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.src/core/data/particles/particle_array.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.src/core/def.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.src/core/utilities/cellmap.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.src/core/vector.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.
🔇 Additional comments (9)
src/core/data/particles/particle_array.hpp (1)
Line range hint
1-424
: Overall assessment: Changes align with PR objectives and improve class functionality.The modifications to the
ParticleArray
class enhance its flexibility and efficiency, which aligns well with the PR objective of minimizing save/restore allocations. The new constructor signature, data access methods, andreplace_from
overload provide more efficient ways to create, access, and manipulate particle data.Key improvements:
- More flexible object creation with default constructor parameters.
- Direct access to underlying data for performance-critical operations.
- Efficient replacement of particle data from external sources.
These changes should contribute to the reported performance improvements in the harris algorithm execution.
To further improve the code:
- Add comprehensive documentation for new and modified functions.
- Consider additional error checking and input validation where appropriate.
- Evaluate any potential impacts on encapsulation and consider if any additional abstraction layers are needed.
src/amr/solvers/solver_ppc.hpp (8)
8-8
: Include necessary header forcore::MinimizingVector
Including
"core/vector.hpp"
is appropriate ascore::MinimizingVector
is utilized in theSaveState
struct.
22-22
: Includecellmap.hpp
forcore::CellMap
usageThe inclusion of
"core/utilities/cellmap.hpp"
is necessary for thecore::CellMap
type used within theSaveState
struct.
28-28
: Include<tuple>
for usage ofstd::forward_as_tuple
Adding
#include <tuple>
ensures thatstd::forward_as_tuple
used inSaveState
is properly declared.
135-135
: Improved const-correctness insaveState_
methodChanging the parameters of
saveState_
toconst&
enhances safety by preventing unintended modifications tolevel
andviews
.
153-177
: Introduction ofSaveState
struct enhances state managementThe new
SaveState
struct provides a structured and efficient approach to managing particle states, which should reduce memory allocations and improve performance during save and restore operations.
179-180
: Extend lifespan of saved states appropriatelyDefining
domainState
andpatchGhostState
at the class scope ensures that the saved states persist as needed between method calls.
227-265
: Efficient state saving insaveState_
methodThe refactored
saveState_
method efficiently captures the state of particles by using theSaveState
struct and minimizes memory allocations, aligning with the PR objectives to enhance performance.
275-290
: Accurate restoration of state inrestoreState_
methodThe
restoreState_
method correctly restores the saved particle states fromSaveState
, ensuring system integrity and consistency after operations.
@@ -31,7 +31,7 @@ class CellMap | |||
|
|||
|
|||
public: | |||
CellMap(Box<cell_index_t, dim> box) | |||
CellMap(Box<cell_index_t, dim> box = {}) |
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.
💡 Codebase verification
🛠️ Refactor suggestion
Potential issues with empty Box
usage in CellMap
The recent change allows creating a CellMap
instance without providing a Box
, which can result in an empty Box
. However, several parts of the codebase use box_
without verifying if it is empty:
loc[i] -= box_.lower[i];
(line 214)cellIndexes_{box.shape().toArray<std::uint32_t>()}
(line 36)
Only one existing check for an empty Box
is found at line 228. This inconsiderate handling may lead to undefined behavior or runtime errors when Box
is empty.
Recommendations:
- Add Null Checks: Ensure all methods accessing
box_
verify that it is not empty before usage. - Handle Initialization Safely: Modify the initialization of
cellIndexes_
to account for an emptyBox
. - Comprehensive Testing: Implement tests to cover scenarios where
CellMap
is initialized with an emptyBox
.
🔗 Analysis chain
Consider the implications of allowing default construction with an empty Box
The addition of a default argument {}
for the box
parameter allows creating a CellMap
instance without explicitly providing a Box
. While this can simplify usage in some cases, it may lead to unintended behavior if the code assumes a non-empty Box
.
Consider the following:
- Ensure that all methods using
box_
(e.g.,addToCell
,size
) can handle an emptyBox
correctly. - Review the initialization of
cellIndexes_
usingbox.shape()
to ensure it behaves correctly with an emptyBox
. - Add documentation to clarify the behavior and potential limitations of using an empty
Box
. - Consider adding an
is_valid()
or similar method to check if theCellMap
has been properly initialized with a non-emptyBox
.
To verify the impact of this change, please run the following script:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential issues with empty Box usage
# Test: Search for methods that use box_ member
echo "Methods potentially affected by empty Box:"
rg --type cpp -n 'box_\.' src/core/utilities/cellmap.hpp
# Test: Check cellIndexes_ initialization
echo "\ncellIndexes_ initialization:"
rg --type cpp -n 'cellIndexes_.*box' src/core/utilities/cellmap.hpp
# Test: Search for existing null checks or empty box handling
echo "\nExisting empty box handling:"
rg --type cpp -n 'box_\.isEmpty\(\)|box_\.empty\(\)' src/core/utilities/cellmap.hpp
Length of output: 679
std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff); | ||
std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff); |
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.
Ensure safe copying of particle data with capacity checks
When using std::copy
to transfer particle data, it's important to ensure that the destination buffers have sufficient capacity to prevent buffer overflows. Consider adding assertions to verify the capacities before copying.
Apply this diff to add capacity checks:
+ assert((doff + dSizes[arr_idx]) <= dParts.capacity());
+ assert((poff + pSizes[arr_idx]) <= pParts.capacity());
std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff);
std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff); | |
std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff); | |
assert((doff + dSizes[arr_idx]) <= dParts.capacity()); | |
assert((poff + pSizes[arr_idx]) <= pParts.capacity()); | |
std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff); | |
std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff); |
src/amr/solvers/solver_ppc.hpp
Outdated
auto operator()() { return std::forward_as_tuple(particles(), sizes(), maps()); } | ||
auto operator()(std::size_t nparts, std::size_t narrays) | ||
{ | ||
if (nparts < particles.capacity()) | ||
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | ||
narrays += narrays * .01; | ||
nparts += nparts * .001; | ||
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | ||
} |
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.
🛠️ Refactor suggestion
Consider increasing capacity growth factors for better performance
In SaveState::operator()
, when nparts
is not less than particles.capacity()
, the increments of nparts += nparts * .001
and narrays += narrays * .01
may not sufficiently increase capacity to prevent frequent reallocations. Consider using larger growth factors, such as doubling the sizes, to optimize performance with large datasets.
Apply this diff to adjust the capacity growth factors:
- narrays += narrays * .01;
- nparts += nparts * .001;
+ narrays = narrays * 2; // Double narrays
+ nparts = nparts * 2; // Double nparts
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
auto operator()() { return std::forward_as_tuple(particles(), sizes(), maps()); } | |
auto operator()(std::size_t nparts, std::size_t narrays) | |
{ | |
if (nparts < particles.capacity()) | |
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | |
narrays += narrays * .01; | |
nparts += nparts * .001; | |
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | |
} | |
auto operator()() { return std::forward_as_tuple(particles(), sizes(), maps()); } | |
auto operator()(std::size_t nparts, std::size_t narrays) | |
{ | |
if (nparts < particles.capacity()) | |
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | |
narrays = narrays * 2; // Double narrays | |
nparts = nparts * 2; // Double nparts | |
return std::forward_as_tuple(particles(nparts), sizes(narrays), maps(narrays)); | |
} |
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.
imagine, nparts is very large, then consider what you're suggested.
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.
@PhilipDeegan, that's a valid point. Doubling nparts
when it's very large could lead to excessive memory usage or undesired behavior. Thank you for pointing this out.
(*´-`)
✏️ Learnings added
Learnt from: PhilipDeegan
PR: PHAREHUB/PHARE#909
File: src/amr/solvers/solver_ppc.hpp:164-172
Timestamp: 2024-10-17T12:43:49.581Z
Learning: When `nparts` is very large, doubling the capacity in `SaveState::operator()` may cause excessive memory usage or overflows. It's important to consider appropriate growth factors to prevent large memory allocations.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
template<bool copy_old = copy_old_> | ||
auto& get(std::size_t const& s) | ||
{ | ||
if (s < v.capacity() * percentile) |
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.
Potential precision loss due to implicit conversion in comparison
In line 18:
if (s < v.capacity() * percentile)
The expression v.capacity() * percentile
results in a double
, while s
is a std::size_t
(an unsigned integer). Comparing an integer to a floating-point number can lead to unexpected behavior due to implicit conversion and precision loss.
Consider explicitly casting the result to std::size_t
to ensure correct comparison:
if (s < static_cast<std::size_t>(v.capacity() * percentile))
This ensures that both sides of the comparison are of the same type, avoiding potential precision issues.
|
||
if (_c == period) | ||
{ | ||
std::vector<T> r(v.capacity() * realloc_to); |
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.
Implicit conversion from double
to size_t
may cause truncation
In line 25:
std::vector<T> r(v.capacity() * realloc_to);
The expression v.capacity() * realloc_to
produces a double
, but the std::vector
constructor expects a size_t
for its size parameter. Implicitly converting a double
to a size_t
can truncate the value, possibly leading to smaller allocations than intended.
Apply this fix to ensure the size is correctly calculated:
- std::vector<T> r(v.capacity() * realloc_to);
+ std::vector<T> r(static_cast<std::size_t>(v.capacity() * realloc_to));
Alternatively, you can use rounding functions if partial capacities should influence the size:
std::vector<T> r(static_cast<std::size_t>(std::ceil(v.capacity() * realloc_to)));
auto& operator()() { return v; } | ||
auto& operator()() const { return v; } | ||
auto& operator()(std::size_t const& s) { return get(s); } |
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.
🛠️ Refactor suggestion
Overloading operator()
may reduce code readability
Overloading the function call operator to access or modify the internal vector can be confusing, as it's unconventional for object manipulation.
Lines 38-40:
auto& operator()() { return v; }
auto& operator()() const { return v; }
auto& operator()(std::size_t const& s) { return get(s); }
Consider using explicit member function names for clarity:
- Replace
operator()()
withdata()
to access the vector. - Replace
operator()(std::size_t const& s)
withresize(s)
or retainget(s)
.
Refactored example:
auto& data() { return v; }
auto& data() const { return v; }
auto& resize(std::size_t const& s) { return get(s); }
This makes the interface more intuitive and improves code expressiveness.
e576417
to
3c384a8
Compare
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.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (7)
src/core/data/particles/particle_array.hpp (4)
Line range hint
44-49
: LGTM: Constructor update improves flexibility.The updated constructor with default parameters allows for more flexible instantiation of
ParticleArray
. This change simplifies usage in some scenarios while maintaining the necessary checks for valid initialization.Consider adding a comment explaining the significance of the
box_
size assertion to improve code readability and maintainability.
76-78
: LGTM: New data() functions enhance flexibility.The addition of
data()
member functions, both const and non-const, provides direct access to the underlying particle data. This enhances the flexibility of theParticleArray
class. The use of theNO_DISCARD
attribute is a good practice to prevent accidental value discard.Consider adding brief documentation comments for these functions to clarify their purpose and any potential risks associated with direct data access.
247-254
: LGTM: New replace_from overload enhances functionality.The new
replace_from
overload provides an efficient way to replace the entire particle array from raw data. It correctly resizes the array, updates the cell map, and copies the particles usingstd::copy
.Consider adding bounds checking or assertions to ensure that the provided
size
matches the size of themap
. This would help prevent potential buffer overruns or inconsistencies between the particle data and the cell map.
Line range hint
1-424
: Overall: Solid improvements to ParticleArray class.The changes to the
ParticleArray
class enhance its flexibility and functionality without introducing major architectural changes or performance issues. The new constructor signature,data()
functions,map()
function, andreplace_from
overload are well-integrated and consistent with the existing code style.These modifications provide more options for initializing and manipulating particle data, which should improve the usability of the class in various scenarios. The changes maintain good const correctness and don't appear to introduce any thread safety issues.
As the
ParticleArray
class continues to evolve, consider documenting the thread safety guarantees (or lack thereof) for the class. This will be valuable for users of the class, especially in parallel computing contexts often found in particle simulations.src/amr/solvers/solver_ppc.hpp (3)
153-175
:SaveState
struct looks well-designed, consider adding documentation.The
SaveState
struct effectively encapsulates particle state data usingcore::MinimizingVector
for optimized memory usage. Theoperator()
overloads provide flexible access to the stored data.Consider adding brief documentation comments to explain the purpose of the struct and its members, especially the significance of the
copy_old
flag.
225-262
: ImprovedsaveState_
method, consider adding capacity checks.The refactored
saveState_
method effectively uses the newSaveState
struct and improves const-correctness. The use ofstd::copy
for transferring particle data is efficient.However, consider adding explicit capacity checks before copying data to prevent potential buffer overflows:
+ assert(doff + dSizes[arr_idx] <= dParts.capacity()); + assert(poff + pSizes[arr_idx] <= pParts.capacity()); std::copy(dInParts.data(), dInParts.data() + dSizes[arr_idx], dParts.data() + doff); std::copy(pInParts.data(), pInParts.data() + pSizes[arr_idx], pParts.data() + poff);
Line range hint
153-287
: Effective refactoring for optimized particle data management.The introduction of the
SaveState
struct and the refactoring ofsaveState_
andrestoreState_
methods significantly improve the particle data management in theSolverPPC
class. These changes likely contribute to better memory efficiency and performance, aligning well with the PR objective of minimizing save/restore allocations.The refactoring maintains the overall functionality of the class while introducing a more structured approach to handling particle data. This should lead to improved maintainability and potentially better performance in particle-heavy simulations.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (5)
- src/amr/solvers/solver_ppc.hpp (6 hunks)
- src/core/data/particles/particle_array.hpp (4 hunks)
- src/core/def.hpp (1 hunks)
- src/core/utilities/cellmap.hpp (1 hunks)
- src/core/vector.hpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/core/def.hpp
- src/core/utilities/cellmap.hpp
- src/core/vector.hpp
🧰 Additional context used
📓 Path-based instructions (2)
src/amr/solvers/solver_ppc.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.src/core/data/particles/particle_array.hpp (1)
Pattern
**/*.hpp
: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.
🔇 Additional comments (3)
src/core/data/particles/particle_array.hpp (1)
234-234
: LGTM: New map() function improves accessibility.The addition of the
map()
member function enhances the accessibility of the cell mapping functionality. It provides const access to the internalcellMap_
member, which is consistent with good encapsulation practices.src/amr/solvers/solver_ppc.hpp (2)
8-8
: New includes look good.The addition of
core/vector.hpp
,core/utilities/cellmap.hpp
, and<tuple>
headers suggests the introduction of new data structures and utilities, which aligns with the changes in the code. These inclusions are appropriate for the refactoring that has been done.Also applies to: 22-22, 28-28
270-287
:restoreState_
method looks good.The refactored
restoreState_
method effectively uses theSaveState
struct to restore particle data. The use of thereplace_from
method for both domain and patch ghost particles is appropriate and likely optimized for this use case. The method correctly handles the restoration of particle data for multiple populations.
experimental |
master 800**2 harris for 10 timesteps
perf stat mpirun -n 8 python3 -Ou harris.py
vs this PR
Summary by CodeRabbit
New Features
SaveState
struct for improved state management of particles.ParticleArray
constructor for easier instantiation.isUsable
andisSettable
added for enhanced usability checks.CellMap
constructor.MinimizingVector
struct for efficient dynamic vector management.Bug Fixes