-
Notifications
You must be signed in to change notification settings - Fork 104
Pvcode + Cvode improvements #2889
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
base: next
Are you sure you want to change the base?
Conversation
dschwoerer
commented
Mar 19, 2024
- Exposes more options to the user.
- Allows to dump if the solver fails. This can be useful for figuring out why the solver is slow. Currently only for pvode, but should also be possible to implement this for cvode (for cvode we can use a documented API)
Use the new track feature (better name required) to dump the different components of the ddt() as well as the residuum for the evolved fields.
This keeps track of all the changes done to the field and stores them to a OptionsObject.
This keeps track of all the changes done to the field and stores them to a OptionsObject.
|
My worry here is the tracking storing a lot of data if it's storing the full |
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.
clang-tidy made some suggestions
It could be, but I don't think it is needed. I would personally keep it enabled for production runs, as it has a runtime switch, that is disabled by default. And I would also keep it like this, at least by default. If a simulation crashes, it can be very useful to immediately get why it failed (this is currently the only use of the name tracking). Having to restart + queue again, just to get to the point where it crashes can be very time consuming, and the cost should be really negligable, if disabled. I did notice a slow down in my simulations with this enabled, but that was when it was enabled all the time and the names did not get reset, thus the names have been growing exponentially. |
|
On 3/19/24 16:34, Peter Hill wrote:
***@***.**** commented on this pull request.
------------------------------------------------------------------------
In include/bout/field.hxx
<#2889 (comment)>:
> @@ -683,4 +683,12 @@ inline T floor(const T& var, BoutReal f, const std::string& rgn = "RGN_ALL") {
#undef FIELD_FUNC
+template <typename T, typename = bout::utils::EnableIfField<T>, class... Types>
+inline T setName(T&& f, const std::string& name, Types... args) {
I think most other setters like this are member functions
But then they return either Field, or need to be overwritten.
|
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.
clang-tidy made some suggestions
src/solver/impls/pvode/pvode.cxx
Outdated
| // Check return flag | ||
| if (flag != SUCCESS) { | ||
| output_error.write("ERROR CVODE step failed, flag = {:d}\n", flag); | ||
| CVodeMemRec* cv_mem = (CVodeMem)cvode_mem; |
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.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
CVodeMemRec* cv_mem = (CVodeMem)cvode_mem;
^|
The cuda build fails with: The relevant code is: (*tracking)[outname].setAttributes({
{"operation", operation},
#if BOUT_USE_TRACK
{"rhs.name", change.name},
#endif
});Is gcc9.4 not able to use setAttributes? |
We do try to completely remove debugging features for production runs, see
This is true, but I would really like to understand the costs. It looks like it's storing potentially hundreds or thousands of copies of full fields, so although it looks like a really interesting and useful feature, it would be good to have a good idea of the costs.
Is that with the current form?
It should almost certainly return |
If at all, I would be in favor of adding a new configure flag. I use this in runs with CHECK=0.
It is only storing fields, if the solver has failed. Unless that happens, no additional storage is used. In the case the solver crashes, I think the cost is really negligible. This is only done once, if the solver decided it cannot continue. For hermes-2, the dump file contains 53 But if BOUT++ runs out of memory here, it would not be much worse then if not - the simulation finishes anyway.
No, currently it is not noticeable. I activate it for all my runs.
That is exactly what I tried: diff --git a/include/bout/field.hxx b/include/bout/field.hxx
index 04035f5b7..488aecaab 100644
--- a/include/bout/field.hxx
+++ b/include/bout/field.hxx
@@ -84,6 +84,14 @@ public:
return *this;
}
+ template <class... Types>
+ inline Field& setName(const std::string& name, Types... args) {
+#if BOUT_USE_TRACK
+ this->name = fmt::format(name, args...);
+#endif
+ return *this;
+ }
+
std::string name;
#if CHECK > 0
@@ -683,19 +691,4 @@ inline T floor(const T& var, BoutReal f, const std::string& rgn = "RGN_ALL") {
#undef FIELD_FUNC
-template <typename T, typename = bout::utils::EnableIfField<T>, class... Types>
-inline void setName(T& f, const std::string& name, Types... args) {
-#if BOUT_USE_TRACK
- f.name = fmt::format(name, args...);
-#endif
-}
-
-template <typename T, typename = bout::utils::EnableIfField<T>, class... Types>
-inline T setName(T&& f, const std::string& name, Types... args) {
-#if BOUT_USE_TRACK
- f.name = fmt::format(name, args...);
-#endif
- return f;
-}
-
#endif /* FIELD_H */
diff --git a/src/mesh/coordinates.cxx b/src/mesh/coordinates.cxx
index 32774d622..643e148b1 100644
--- a/src/mesh/coordinates.cxx
+++ b/src/mesh/coordinates.cxx
@@ -1542,7 +1542,7 @@ Field3D Coordinates::Grad_par(const Field3D& var, CELL_LOC outloc,
TRACE("Coordinates::Grad_par( Field3D )");
ASSERT1(location == outloc || outloc == CELL_DEFAULT);
- return setName(::DDY(var, outloc, method) * invSg(), "Grad_par({:s})", var.name);
+ return (::DDY(var, outloc, method) * invSg()).setName("Grad_par({:s})", var.name);
}
/////////////////////////////////////////////////////////
@@ -1601,7 +1601,7 @@ Field3D Coordinates::Div_par(const Field3D& f, CELL_LOC outloc,
f_B.yup(i) = f.yup(i) / Bxy_floc.yup(i);
f_B.ydown(i) = f.ydown(i) / Bxy_floc.ydown(i);
}
- return setName(Bxy * Grad_par(f_B, outloc, method), "Div_par({:s})", f.name);
+ return (Bxy * Grad_par(f_B, outloc, method)).setName("Div_par({:s})", f.name);
}
/////////////////////////////////////////////////////////
diff --git a/src/solver/impls/pvode/pvode.cxx b/src/solver/impls/pvode/pvode.cxx
index db28f64d8..c36985ae0 100644
--- a/src/solver/impls/pvode/pvode.cxx
+++ b/src/solver/impls/pvode/pvode.cxx
@@ -376,7 +376,7 @@ BoutReal PvodeSolver::run(BoutReal tout) {
for (auto& f : f3d) {
f.F_var->enableTracking(fmt::format("ddt_{:s}", f.name), debug);
- setName(*f.var, f.name);
+ f.var->setName(f.name);
}
run_rhs(simtime);gcc14 complains with: |
gcc 9.4 is unable to correctly parse the construction for the function argument, if name.change is used directly. First making a copy seems to work around that issue.
|
@dschwoerer After discussing this with @bendudson, we're quite concerned about the potential overhead of the temporary field dumping mechanism, both in terms of memory and performance, for what seems like a small benefit when debugging. We'd really like to see some performance analysis and scaling to see it doesn't have an affect when disabled. I'm also worried that we'd need to see Could something similar not be achieved with a custom monitor instead? Exposing more CVODE options to the user seems very straightforward and useful, so maybe that could be split out? |
But the memory overhead is only if the solver fails. Do you still think at that point that is an issue?
I can certainly run blob2d for this branch and next. But I am certain there are no significant differences, thus I haven't done it. Would you like to see something else? Would just the BOUT++ internal timings sufficient? Would you like mpi runs?
Sure, having them makes things more easily readable. But that is optional, and I can certainly add some if you think this is worth merging an wanted before merging. It would make
I would not know how. If you can explain how to, I am happy to change the design.
I can split them out 👍 |
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.
clang-tidy made some suggestions
|
With cb0d3f1 setName is not that important anymore. The stacktrace is stored, so it is fairly easy to reliably figure out where things are comming from :-) We could remove setName again, if that is desired ... |
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.
clang-tidy made some suggestions
I think I addressed all requested changes
c8c1180 to
3cc061b
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.
clang-tidy made some suggestions
ZedThree
left a comment
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.
There's some minor bits that would be nice to tidy up.
Please could you also:
- add something about this to the debugging section in the manual?
- change the PR title to something about tracking field operations for debugging?
src/solver/impls/euler/euler.cxx
Outdated
|
|
||
| if (mesh != nullptr) { | ||
| mesh->outputVars(debug); | ||
| debug["BOUT_VERSION"].force(bout::version::as_double); |
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.
Could do:
| debug["BOUT_VERSION"].force(bout::version::as_double); | |
| bout::experimental::addBuildFlagsToOptions(debug); |
but the extra bits probably not necessary?
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 do not think they are needed. I have moved it to the function, so we can change it later all in one place 👍
src/solver/impls/pvode/pvode.cxx
Outdated
| const std::string outname = fmt::format( | ||
| "{}/BOUT.debug.{}.nc", | ||
| Options::root()["datadir"].withDefault<std::string>("data"), BoutComm::rank()); | ||
|
|
||
| bout::OptionsIO::create(outname)->write(debug); |
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.
Same comment as for the euler solver. In fact, if it's possible we might want to add this in more places, maybe worth a helper function to create these files?
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 it should be possible. The CVode solver even has a documented API to get the residua :-)
Allows to use other backends then netcdf
Co-authored-by: Peter Hill <peter.hill@york.ac.uk>
|
Should be ready for re-review @ZedThree |
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.
clang-tidy made some suggestions
include/bout/options_io.hxx
Outdated
| /// Write some data to a file with a given name prefix | ||
| /// This will be done in parallel. If Mesh is given, also mesh data will be | ||
| /// added, which is needed for xBOUT or boutdata to read the files. | ||
| static void write(const std::string& prefix, Options data, Mesh* mesh = nullptr); |
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.
warning: no header providing "Mesh" is directly included [misc-include-cleaner]
include/bout/options_io.hxx:41:
- #ifndef OPTIONS_IO_H
+ #include "bout/field2d.hxx"
+ #ifndef OPTIONS_IO_H| #include <bout/openmpwrap.hxx> | ||
| #include <bout/output.hxx> | ||
| #include <bout/version.hxx> | ||
|
|
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.
warning: included header version.hxx is not used directly [misc-include-cleaner]
| const std::string outnumber = | ||
| dump_at_time < -3 ? fmt::format(".{}", debug_counter++) : ""; | ||
| const std::string outname = fmt::format("BOUT.debug{}", outnumber); | ||
| bout::OptionsIO::write(outname, debug, mesh); |
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.
warning: 'Options' is deprecated: Please use a reference or .copy() instead [clang-diagnostic-deprecated-declarations]
bout::OptionsIO::write(outname, debug, mesh);
^Additional context
include/bout/options.hxx:254: 'Options' has been explicitly marked deprecated here
[[deprecated("Please use a reference or .copy() instead")]] Options(
^| const std::string outnumber = | ||
| dump_at_time < -3 ? fmt::format(".{}", debug_counter++) : ""; | ||
| const std::string outname = fmt::format("BOUT.debug{}", outnumber); | ||
| bout::OptionsIO::write(outname, debug, mesh); |
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.
warning: no header providing "bout::OptionsIO" is directly included [misc-include-cleaner]
src/solver/impls/euler/euler.cxx:2:
- #include <bout/boutcomm.hxx>
+ #include "bout/options_io.hxx"
+ #include <bout/boutcomm.hxx>| #include <bout/sys/timer.hxx> | ||
| #include <bout/unused.hxx> | ||
| #include <bout/version.hxx> | ||
|
|
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.
warning: included header version.hxx is not used directly [misc-include-cleaner]
| for (auto& f : f3d) { | ||
| saveParallel(debug, f.name, *f.var); | ||
| } | ||
| bout::OptionsIO::write("BOUT.debug", debug, mesh); |
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.
warning: no header providing "bout::OptionsIO" is directly included [misc-include-cleaner]
src/solver/impls/pvode/pvode.cxx:26:
+ #include "bout/options_io.hxx"