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

ci: Enable standard library assertions in debug builds #3759

Merged
merged 12 commits into from
Dec 11, 2024

Conversation

benjaminhuth
Copy link
Member

@benjaminhuth benjaminhuth commented Oct 18, 2024

Should add assertions that check preconditions of calls to standardlibrary functions.

Summary by CodeRabbit

  • Chores
    • Enhanced configuration for compiler flags to conditionally enable assertions.
    • Addressed compilation issues with GCC 13 by undefining specific preprocessor directives.
    • Maintained existing logic for compiler type checks without altering public entity signatures.
  • Bug Fixes
    • Adjusted the logic for generating random directions to ensure correct bounds for angles.
  • Documentation
    • Improved comments for clarity on the calculations in the random direction generation function.

@benjaminhuth benjaminhuth added this to the next milestone Oct 18, 2024
@github-actions github-actions bot added the Infrastructure Changes to build tools, continous integration, ... label Oct 18, 2024
@paulgessinger
Copy link
Member

paulgessinger commented Oct 18, 2024

Maybe we should put this behind an option and enable it explicitly in the CI? That way we wouldn't silently modify local Debug builds. We could also reuse the ACTS_FORCE_ASSERTIONS flag.

I'm definitely uncomfortable with adding this to RelWithDebInfo.

@benjaminhuth
Copy link
Member Author

Hmm I added it also for clang... but actually, I do not check which stdlib is used. Maybe we should add both macros unconditionally of the CMAKE_COMPILER_ID.

Regarding the option, you mean to avoid rebuild after this PR?

@paulgessinger
Copy link
Member

paulgessinger commented Oct 18, 2024

@benjaminhuth I don't think we should unexpectedly enable any assertions outside of the CI, even in Debug builds. But if you gate this with ACTS_FORCE_ASSERTIONS, which we turn on in the CI, and don't make it depend on the build type, we could still get the assertions there.

@benjaminhuth
Copy link
Member Author

Okay yeah that makes sense, ACTS_FORCE_ASSERTIONS seems a good place to do this I haven't though of.

@benjaminhuth
Copy link
Member Author

But just out of interest @paulgessinger: To me every standard library assertion would be a violated precondition, so what would be the issue with enabling them for RelWithDebMode?

GCC documentation even recommendes them for production builds actually (https://gcc.gnu.org/wiki/LibstdcxxDebugMode)

Copy link

github-actions bot commented Oct 18, 2024

📊: Physics performance monitoring for 6033b24

Full contents

physmon summary

@paulgessinger
Copy link
Member

paulgessinger commented Oct 18, 2024

@benjaminhuth I don't see it being recommended, just that it's suitable to run in production. It's a HUGE change to enable e.g. bounds checking quietly. ATLAS builds with RelWithDebInfo, so we'd force any compilation unit compiled in Athena that links with ACTS to have these assertions on. That'd be super disruptive.

@benjaminhuth
Copy link
Member Author

Yeah I agree that its a huge change, but would be a good change in my opinion. But yeah, I wasn't aware that by default acts is build in RelWithDebInfo for production builds in ATLAS. Thats of course a different story then...

@paulgessinger
Copy link
Member

paulgessinger commented Oct 18, 2024

Yeah I agree that its a huge change, but would be a good change in my opinion.

Sure, but there's no way we can decide this as a library. We can test with these assertions on (which is a very good idea imo), and experiments can then decide if they want them, but there's no way we can force this.

@andiwand
Copy link
Contributor

Also this does not come for free right? I guess the standard lib functions will do extra checks which are skipped otherwise. So it is a bit like with our assertions while ours might be more expensive

@paulgessinger
Copy link
Member

@andiwand I believe these are reasonably light checks, like bounds checks or smart pointer nullptr checks, which a reasonable branch predictor will probably get right most of the time (at least that's the justification for this in Rust land). So @benjaminhuth is probably right that they're not terrible for performance and are likely safe for production use.

@paulgessinger
Copy link
Member

paulgessinger commented Oct 18, 2024

Seems like the detray conversion code does some out-of-bounds access, which ostensibly with these flags are checked at compile-time.

/usr/include/c++/13/bits/stl_algobase.h:437:30: error: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' forming offset [16, 17] is out of the bounds [0, 16] of object '<anonymous>' with type 'const double [2]' [-Werror=array-bounds=]
  437 |             __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
      |             ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/__w/acts/acts/Plugins/Json/src/DetrayJsonHelper.cpp: In function 'std::tuple<unsigned int, std::vector<double, std::allocator<double> > > Acts::DetrayJsonHelper::maskFromBounds(const Acts::SurfaceBounds&, bool)':
/__w/acts/acts/Plugins/Json/src/DetrayJsonHelper.cpp:46:47: note: '<anonymous>' declared here
   46 |         boundaries = {bValues[0u], bValues[1u]};
      |                                               ^
cc1plus: all warnings being treated as errors

@benjaminhuth
Copy link
Member Author

I'll go into this later/next week

@andiwand
Copy link
Contributor

@andiwand I believe these are reasonably light checks, like bounds checks or smart pointer nullptr checks, which a reasonable branch predictor will probably get right most of the time (at least that's the justification for this in Rust land). So @benjaminhuth is probably right that they're not terrible for performance and are likely safe for production use.

Right but ultimately this is something which should be measured before being deployed anywhere

@paulgessinger
Copy link
Member

@andiwand And despite all of this, it should be off-by-default.

@github-actions github-actions bot added the Stale label Nov 29, 2024
Copy link

coderabbitai bot commented Nov 29, 2024

Walkthrough

Conditional logic for compiler flags, added it is. In cmake/ActsCompilerOptions.cmake, if ACTS_FORCE_ASSERTIONS defined, -D_GLIBCXX_ASSERTIONS and -D_LIBCPP_DEBUG flags appended to cxx_flags. Existing logic for compiler types, intact it remains. Modifications to angle calculations in Core/include/Acts/EventData/detail/GenerateParameters.hpp, correct they are. Preprocessor directives in Plugins/Json/src/DetrayJsonHelper.cpp, introduced to undefine assertions. No changes to exported entities, there are.

Changes

File Change Summary
cmake/ActsCompilerOptions.cmake Added conditional logic for compiler flags based on ACTS_FORCE_ASSERTIONS variable. Flags -D_GLIBCXX_ASSERTIONS and -D_LIBCPP_DEBUG added to cxx_flags. Existing compiler checks preserved.
Core/include/Acts/EventData/detail/GenerateParameters.hpp Modified generateBoundDirection function to correct angle calculations. Adjusted cosThetaMin, cosThetaMax, etaMin, and etaMax derivations for proper bounds. Minor comment clarifications included.
Plugins/Json/src/DetrayJsonHelper.cpp Introduced preprocessor directives to undefine _GLIBCXX_ASSERTIONS and _LIBCPP_DEBUG. Core functionality of maskFromBounds remains unchanged, with improved handling of SurfaceBounds types.

Possibly related PRs

  • refactor: FPE safe eta/theta conversion #3788: The changes in this PR involve modifications to the logic of angle conversions between eta and theta, which may relate to the conditional compiler flags for assertions in the main PR, as both involve enhancing the robustness of calculations and configurations in the codebase.

Suggested labels

automerge, coderabbit

Suggested reviewers

  • paulgessinger

Poem

In the land of code, new flags arise,
Assertions now dance, under clear skies.
With logic so clever, conditions align,
A compiler's delight, oh how it does shine!
Yoda approves, for changes are wise,
In the realm of CMake, new power lies! 🌟


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?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a 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 (1)
cmake/ActsCompilerOptions.cmake (1)

16-19: Wisdom to share about stdlib assertions, I have.

Hmmmm. Both stdlib assertion flags added unconditionally, I see. Correct this approach is, as work it will regardless of stdlib used. But document the impact of these assertions, we must.

Consider these suggestions, you should:

  • Add comments explaining the purpose and impact of each flag
  • Document performance implications in debug builds
  • Clarify behavior in different build types
 # Add assertions to standard libraries
+# _GLIBCXX_ASSERTIONS: Enables assertions in GNU libstdc++ (bounds checking, etc.)
+# _LIBCPP_DEBUG: Enables assertions in LLVM libc++ (iterator validation, etc.)
+# Note: Both flags are added as they are no-op if the respective stdlib is not used
 if(ACTS_FORCE_ASSERTIONS)
     set(cxx_flags "${cxx_flags} -D_GLIBCXX_ASSERTIONS -D_LIBCPP_DEBUG")
 endif()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 0b8e768 and e1e47db.

📒 Files selected for processing (1)
  • cmake/ActsCompilerOptions.cmake (1 hunks)
🔇 Additional comments (1)
cmake/ActsCompilerOptions.cmake (1)

17-17: Verify the impact on build configurations, we must.

Control these assertions based on build type, consider you should. In RelWithDebInfo builds, careful we must be.

✅ Verification successful

Hmm, clear the path forward is now. Concerns about build configurations, address we can.

From the gathered wisdom, observe I do:

  • RelWithDebInfo is the default build type, set in cmake/ActsCompilerOptions.cmake it is
  • ACTS_FORCE_ASSERTIONS already properly handled it is:
    • When enabled, adds -D_GLIBCXX_ASSERTIONS and -D_LIBCPP_DEBUG flags it does
    • Optional feature it remains, OFF by default it is
    • Clear warning message about side effects, present in CMakeLists.txt it is

No changes needed I see. The current implementation, wise it already is. Control assertions based on build type? Through ACTS_FORCE_ASSERTIONS flag, achieved it already is. Optional and explicit the control remains, as it should be.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how ACTS_FORCE_ASSERTIONS is used across different build configurations

# Search for build type configurations
rg -A 5 "CMAKE_BUILD_TYPE|ACTS_FORCE_ASSERTIONS" 

# Look for any existing assertion-related configuration
fd -e cmake -e txt -x rg "ASSERTIONS|DEBUG|NDEBUG"

Length of output: 7516

@github-actions github-actions bot removed the Stale label Nov 29, 2024
@github-actions github-actions bot added the Component - Core Affects the Core module label Dec 9, 2024
Copy link

@coderabbitai coderabbitai bot left a 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 (1)
Core/include/Acts/EventData/detail/GenerateParameters.hpp (1)

109-118: Add assertions for parameter bounds, we should.

In alignment with PR objectives of enabling standard library assertions, add parameter validation we must. Verify that:

  • thetaMin <= thetaMax
  • phiMin <= phiMax

Apply this enhancement, you should:

 template <typename generator_t>
 inline std::pair<double, double> generateBoundDirection(
     generator_t& rng, const GenerateBoundDirectionOptions& options) {
+  assert(options.thetaMin <= options.thetaMax && "Invalid theta range");
+  assert(options.phiMin <= options.phiMax && "Invalid phi range");
+
   using UniformReal = std::uniform_real_distribution<double>;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e1e47db and 11c99ba.

📒 Files selected for processing (1)
  • Core/include/Acts/EventData/detail/GenerateParameters.hpp (1 hunks)
🔇 Additional comments (2)
Core/include/Acts/EventData/detail/GenerateParameters.hpp (2)

117-118: Consistent with theta changes, the eta calculations are.

Aligned with the theta bounds swap, the eta calculations now are. Maintain mathematical harmony between theta and eta transformations, this does.


109-114: Correct, the angle calculations now are, hmmmm.

Swapped the theta bounds in cosine calculations, wisdom shows. Proper spherical coordinates generation, this ensures. Used nextafter() correctly to include upper bound, prevent floating-point exclusion it does.

Run these commands, we must, to verify the test coverage:

✅ Verification successful

Correct the angle calculations are, young padawan

Examined the Force flows through the code, I have. The swapping of thetaMin and thetaMax in cosine calculations, proper it is. Two reasons, there are:

  1. Used twice in the codebase generateBoundDirection is, for creating test parameters in GenerateParameters.hpp. Consistent with spherical coordinate system conventions, this change remains.
  2. The nextafter usage, wisdom shows - ensures the upper bound included is, preventing floating-point exclusion it does.

No test failures this change will cause, as random direction generation for testing purposes only it serves. The Force is strong with this modification.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check test coverage for generateBoundDirection function

# Search for test files using this function
rg -l "generateBoundDirection" --type cpp | grep -i "test"

# Look for specific test assertions on angle ranges
ast-grep --pattern 'BOOST_CHECK$_($_)' | grep -i "theta\|phi\|eta"

Length of output: 125


Script:

#!/bin/bash
# Search for test files containing generateBoundDirection with more context
rg -l "generateBoundDirection" Tests/

# Look for test files specifically in UnitTests directory
rg -l "generateBoundDirection" UnitTests/

# Check for actual usage of the function in tests with context
rg "generateBoundDirection" --type cpp -C 3

# Look for test assertions related to bound parameters
rg "BOOST_" --type cpp | grep -i "bound.*param"

Length of output: 9762

@github-actions github-actions bot added the Component - Plugins Affects one or more Plugins label Dec 10, 2024
paulgessinger
paulgessinger previously approved these changes Dec 11, 2024
Copy link
Member

@paulgessinger paulgessinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple small comments, looks good to me otherwise.

Plugins/Json/src/DetrayJsonHelper.cpp Outdated Show resolved Hide resolved
Core/include/Acts/EventData/detail/GenerateParameters.hpp Outdated Show resolved Hide resolved
cmake/ActsCompilerOptions.cmake Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a 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 (1)
Core/include/Acts/EventData/detail/GenerateParameters.hpp (1)

112-118: Correct, the cosine calculations are! Yet clearer, the comments could be.

Wise decision to flip cosThetaMin and cosThetaMax, it is. For in the realm of [0,π], as theta increases, its cosine decreases. Proper handling of floating-point bounds with std::nextafter, you have achieved.

Enhance the comment clarity, we should:

-  // Get cosThetaMin from thetaMax and vice versa, because cos is
-  // monothonical decreasing between [0, pi]
+  // Get cosThetaMin from thetaMax and vice versa, because:
+  // 1. cos(θ) is monotonically decreasing in [0,π]
+  // 2. For θ₁ < θ₂, cos(θ₁) > cos(θ₂)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 4b3af22 and d98dddd.

📒 Files selected for processing (2)
  • Core/include/Acts/EventData/detail/GenerateParameters.hpp (1 hunks)
  • Plugins/Json/src/DetrayJsonHelper.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Plugins/Json/src/DetrayJsonHelper.cpp
🔇 Additional comments (2)
Core/include/Acts/EventData/detail/GenerateParameters.hpp (2)

105-107: Wise assertions added, they are!

Validate the bounds of theta, these assertions do. Prevent invalid input that could lead to incorrect results or undefined behavior, they will. Strong with the Force, these preconditions are!


121-122: Consistent with theta changes, the eta calculations are!

Correctly flipped, the eta calculations are, maintaining harmony with the theta transformations. Yet verify the impact on downstream calculations, we must.

✅ Verification successful

The previous pattern didn't yield results, so I'm broadening the search to find any usage of these parameters and functions. This will help us verify the impact of the eta calculations change.


Correct and well-tested, the eta-theta transformation is!

Through the Force, seen the truth I have. The relationship between eta and theta, consistently implemented it is across the codebase. In the unit tests at Tests/UnitTests/Core/Utilities/AngleHelpersTests.cpp, verified the mathematical relationship is:

  • Bidirectional transformation tested it is: etaFromTheta(thetaFromEta(eta)) = eta
  • At boundary conditions checked it is
  • For both float and double types, validated it is

The flipped calculations in GenerateParameters.hpp, correct they are:

double etaMin = Acts::AngleHelpers::etaFromTheta(options.thetaMax);
double etaMax = Acts::AngleHelpers::etaFromTheta(options.thetaMin);

For theta and eta, inverse relationship they share - when theta increases, eta decreases. Therefore, the max theta gives min eta, and min theta gives max eta. Mathematical harmony, maintained it is!

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of generateBoundDirection with etaUniform=true
ast-grep --pattern 'generateBoundDirection($_,$_).etaUniform = true'

Length of output: 70


Script:

#!/bin/bash
# Search for usages of generateBoundDirection and etaUniform
rg -A 3 "generateBoundDirection.*etaUniform"

# Search for files that include GenerateParameters.hpp
rg -l '#include.*GenerateParameters\.hpp'

# Search for direct usage of etaFromTheta
rg "etaFromTheta"

Length of output: 3163

kodiakhq bot pushed a commit that referenced this pull request Dec 11, 2024
Pulled out of #3759 

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **Bug Fixes**
	- Enhanced validation for direction generation parameters to ensure they are within acceptable ranges.
	- Adjusted calculations for cosine and eta values to align with the properties of the cosine function.

- **Tests**
	- Modified random distribution ranges in unit tests for the `CylinderVolumeBuilder` to improve test coverage and accuracy.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@kodiakhq kodiakhq bot merged commit 595f2e6 into acts-project:main Dec 11, 2024
42 checks passed
@acts-project-service acts-project-service added the Breaks Athena build This PR breaks the Athena build label Dec 11, 2024
@paulgessinger paulgessinger modified the milestones: next, v38.2.0 Dec 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaks Athena build This PR breaks the Athena build Component - Core Affects the Core module Component - Plugins Affects one or more Plugins Infrastructure Changes to build tools, continous integration, ...
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants