Skip to content
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

Make sure incorrect conversions trigger an exception #722

Merged
merged 6 commits into from Aug 19, 2021
Merged

Conversation

GiovanniBussi
Copy link
Member

@GiovanniBussi GiovanniBussi commented Jul 19, 2021

This is an attempt to fix #717. I am applying it directly to version 2.8 but it might be backported.

Description

OUTDATED, see below

I modified the way the functions Tools::convert() work. Before this change, they were returning a bool (false meant an error). This is a poor design, since the user might ignore the error easily, and was used since in the first PLUMED 2 releases we were not using C++ exceptions yet. After this change, these functions return void and raise an exception in case of an error. This makes it more difficult to inadvertently ignore conversion errors.

Basically, these modifications required me to modify all the places where the return value was correctly checked. All these places were immediately detectable as compilation error since the return value of these functions was accessed. For instance, something like this:

if(Tools::convert(a,b)) do_something();
else do_something_else();

now would not compile unless it is converted to:

try {
  Tools::convert(a,b);
  do_something();
} catch(ExceptionConversionError& exc) {
 do_something_else();
}

In fixing the code I had to adjust some checks in VES and OPES (cc: @valsson and @invemichele).

In addition, I added a workaround to the code since there's a place where conversions were not checked and should not be checked to pass current regtests. More precisely, the original code was not checking the returned value, and, consistently, the new code ignore any exception triggered here. @gtribello please check if the fix is ok or if there's something else to do here. In particular, I think that to pass test multicolvar/rt-dens-average it would be sufficient to allow for empty strings (rather than to allow for arbitrary strings as it is now).

Target release

I would like my code to appear in release v2.8 but could be backported

Type of contribution
  • changes to code or doc authored by PLUMED developers, or additions of code in the core or within the default modules
  • changes to a module not authored by you
  • new module contribution or edit of a module authored by you
Copyright
  • I agree to transfer the copyright of the code I have written to the PLUMED developers or to the author of the code I am modifying.
  • the module I added or modified contains a COPYRIGHT file with the correct license information. Code should be released under an open source license. I also used the command cd src && ./header.sh mymodulename in order to make sure the headers of the module are correct.
Tests
  • I added a new regtest or modified an existing regtest to validate my changes.
  • I verified that all regtests are passed successfully on GitHub Actions.

@GiovanniBussi
Copy link
Member Author

Note: there's something wrong with GitHub actions tests on Linux, I have to check them...

@codecov-commenter
Copy link

codecov-commenter commented Jul 19, 2021

Codecov Report

Merging #722 (df8dbd4) into master (64bc4ec) will increase coverage by 0.03%.
The diff coverage is 93.33%.

❗ Current head df8dbd4 differs from pull request most recent head a773ab6. Consider uploading reports for the commit a773ab6 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master     #722      +/-   ##
==========================================
+ Coverage   85.56%   85.60%   +0.03%     
==========================================
  Files         588      588              
  Lines       47670    47680      +10     
==========================================
+ Hits        40790    40815      +25     
+ Misses       6880     6865      -15     
Impacted Files Coverage Δ
src/core/CLTool.h 74.19% <50.00%> (ø)
src/vesselbase/Vessel.h 81.25% <50.00%> (ø)
src/tools/Tools.cpp 90.86% <88.88%> (-0.92%) ⬇️
src/core/Action.h 92.42% <100.00%> (ø)
src/core/ActionAtomistic.cpp 92.21% <100.00%> (ø)
src/core/PlumedMain.cpp 90.03% <100.00%> (+0.03%) ⬆️
src/core/Value.cpp 83.11% <100.00%> (ø)
src/gridtools/GridVessel.cpp 94.42% <100.00%> (ø)
src/opes/OPESmetad.cpp 94.97% <100.00%> (ø)
src/tools/PDB.cpp 80.98% <100.00%> (+0.14%) ⬆️
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 64bc4ec...a773ab6. Read the comment docs.

I changed the code in private convertTo* functions to the original
form (return bool). This is actually faster when exceptions are raised
frequently. In this manner, I solve the performance issue on Linux.
In the original fix I was making convert() throw exceptions.
However, we use a lot failed conversions when reading inputs.
Since catching an exception is much more expensive than inspecting
a returned bool, this was slowing down a lot some parts of the code

In 0ed75e9 I solved the issue
by allowing to throw only a few functions.

Here I take a radically different approach: a new function (convertNoexcept)
can be used like to old one, and returns a bool. The function
convert just calls convertNoexcept and, if false, throws.

In this manner there is no overhead expected at all with respect to the
previous version of the code.

In addition, the modifications are less intrusive. It is sufficient to
replace convert with convertNoexcept in all the places where the returned
bool was checked
@GiovanniBussi
Copy link
Member Author

After having seen that there is a performance penalty in catching exception, I made an alternative implementation where exceptions are only used when needed. In the new implementation:

  • convertNoexcept(a,b) is identical to the old convert. It returns a bool that one is then expected to check manually. This can be used in place where we were correctly checking the returned value
  • convert(a,b) basically calls plumed_assert(convert(a,b)). It will automatically be used anywhere we do not check the output

The advantage with respect to the previous implementation is that we only throw exceptions when the is a non-detected error. We can still repeatedly call covertNoexcept to check if a given number can be converted without performance penalties.

The changes to the code are also simpler since there's no need to add try/catch statements.

@gtribello there is still this point to double check. In order not to break a test, I am ignoring the result here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Issue with GRID_MIN/GRID_MAX in HISTOGRAM action
3 participants