diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f327dae..6edff808 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -389,7 +389,7 @@ jobs: -Dtest_data_file=$(pwd)/test_data.hipo \ -Dtest_num_events=${{ env.num_events }} \ -Dtest_output_dir=$(pwd)/validation_results \ - -Dtest_multithreading=${{ env.num_threads }} \ + -Dtest_num_threads=${{ env.num_threads }} \ ${{ matrix.opts }} - name: dump all build options run: meson configure iguana_build --no-pager @@ -413,6 +413,7 @@ jobs: - run: tree iguana ### run tests - name: meson test + if: ${{ matrix.id != 'documentation' }} working-directory: iguana_build run: | if [ "${{ env.verbose_test }}" = "true" ]; then @@ -423,26 +424,26 @@ jobs: fi ### run benchmarks - name: benchmark algorithms - if: ${{ matrix.id == 'coverage' }} # use the coverage job's GITHUB_STEP_SUMMARY + if: ${{ matrix.id == 'cpp' && inputs.id == 'linux-latest' }} run: | for suite in single_threaded memoize; do meson test --benchmark --suite $suite -C iguana_build | tee benchmark_$suite.txt done iguana_src/.github/make-benchmark-table.rb benchmark_{single_threaded,memoize}.txt | xargs -0 -I{} echo {} >> $GITHUB_STEP_SUMMARY ### coverage - # - name: coverage - # if: ${{ matrix.id == 'coverage' }} - # run: | - # ninja -C iguana_build coverage-html - # ninja -C iguana_build coverage-text - # mv iguana_build/meson-logs/coveragereport coverage-report - # echo '### Coverage Report' >> $GITHUB_STEP_SUMMARY - # echo '```' >> $GITHUB_STEP_SUMMARY - # cat iguana_build/meson-logs/coverage.txt >> $GITHUB_STEP_SUMMARY - # echo '```' >> $GITHUB_STEP_SUMMARY - # echo '' >> $GITHUB_STEP_SUMMARY - # echo '- for details, see the `coverage-report` artifact' >> $GITHUB_STEP_SUMMARY - # echo '- to compare to the report from the `main` branch, see ' >> $GITHUB_STEP_SUMMARY + - name: coverage + if: ${{ matrix.id == 'coverage' }} + run: | + ninja -C iguana_build coverage-html + ninja -C iguana_build coverage-text + mv iguana_build/meson-logs/coveragereport coverage-report + echo '### Coverage Report' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat iguana_build/meson-logs/coverage.txt >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo '' >> $GITHUB_STEP_SUMMARY + echo '- for details, see the `coverage-report` artifact' >> $GITHUB_STEP_SUMMARY + echo '- to compare to the report from the `main` branch, see ' >> $GITHUB_STEP_SUMMARY ### test relocatability - name: test relocatability if: ${{ matrix.id == 'cpp' }} # don't bother re-running santizers, etc. @@ -511,13 +512,13 @@ jobs: name: meson_logs_${{ matrix.id }} retention-days: 5 path: iguana_build/meson-logs - # - name: upload coverage artifacts - # uses: actions/upload-artifact@v4 - # if: ${{ matrix.id == 'coverage' }} - # with: - # name: coverage-report - # retention-days: 5 - # path: coverage-report + - name: upload coverage artifacts + uses: actions/upload-artifact@v4 + if: ${{ matrix.id == 'coverage' }} + with: + name: coverage-report + retention-days: 5 + path: coverage-report - name: upload validator artifacts uses: actions/upload-artifact@v4 if: ${{ matrix.id == 'cpp' }} @@ -551,18 +552,18 @@ jobs: with: name: doc_doxygen path: doxygen - # - name: download coverage report - # uses: actions/download-artifact@v4 - # with: - # name: coverage-report - # path: coverage-report + - name: download coverage report + uses: actions/download-artifact@v4 + with: + name: coverage-report + path: coverage-report - run: tree - name: collect run: | mkdir pages cp iguana_src/.github/pages-index.html pages/index.html mv doxygen pages/ - # - run: mv coverage-report pages/ + - run: mv coverage-report pages/ - run: tree - uses: actions/upload-pages-artifact@v3 with: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 9e6ace13..7d214298 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -36,7 +36,7 @@ jobs: ], "include": [ { "id": "cpp", "CC": "gcc", "CXX": "g++", "opts": "-Dbuildtype=release -Dz_require_root=true -Dtest_validator_all_stats=true" }, - { "id": "coverage", "CC": "gcc", "CXX": "g++", "opts": "-Dbuildtype=release -Dz_require_root=true -Db_coverage=true" }, + { "id": "coverage", "CC": "gcc", "CXX": "g++", "opts": "-Dbuildtype=release -Dz_require_root=true -Db_coverage=true -Dz_test_multithreading=false" }, { "id": "documentation", "CC": "gcc", "CXX": "g++", "opts": "-Dbuildtype=release -Dz_require_root=true -Dinstall_documentation=true" }, { "id": "address-sanitizer", "CC": "clang", "CXX": "clang++", "opts": "-Dbuildtype=debug -Dz_require_root=true -Db_sanitize=address -Db_lundef=false -Db_pie=true" }, { "id": "thread-sanitizer", "CC": "clang", "CXX": "clang++", "opts": "-Dbuildtype=debug -Dz_require_root=true -Db_sanitize=thread -Db_lundef=false -Db_pie=true" }, diff --git a/meson.options b/meson.options index e916cc99..78cb63eb 100644 --- a/meson.options +++ b/meson.options @@ -11,9 +11,10 @@ option('test_data_file', type: 'string', value: '', description: ' option('test_num_events', type: 'string', value: '10', description: 'Number of events from `test_data_file` to test') option('test_output_dir', type: 'string', value: '', description: 'Output directory for tests. Must be an absolute path. If unspecified, tests will still run, but will not produce output files.') option('test_validator_all_stats', type: 'boolean', value: false, description: 'If true, use all statistics for validators, rather than `test_num_events`') -option('test_multithreading', type: 'integer', value: 4, min: 0, description: 'run multithreading tests with this many threads (use 0 for hardware max)') +option('test_num_threads', type: 'integer', value: 4, min: 0, description: 'run multithreading tests with this many threads (use 0 for hardware max)') # expert options: the defaults should be reasonable for a local installation; different values may be preferred for installation in common areas option('z_install_envfile', type: 'boolean', value: true, description: 'Install a sourceable environment variable file') option('z_require_root', type: 'boolean', value: false, description: 'Fail if ROOT is not found') option('z_require_rcdb', type: 'boolean', value: false, description: 'Fail if RCDB is not found') +option('z_test_multithreading', type: 'boolean', value: true, description: 'Enable multithreading tests') diff --git a/meson/ubsan.supp b/meson/ubsan.supp index 51719faa..4d695fd8 100644 --- a/meson/ubsan.supp +++ b/meson/ubsan.supp @@ -1,6 +1,16 @@ # https://github.com/gavalian/hipo/issues/49 -alignment:hipo::structure::getFloatAt +alignment:hipo::structure::getIntAt alignment:hipo::structure::getShortAt +alignment:hipo::structure::getByteAt +alignment:hipo::structure::getFloatAt alignment:hipo::structure::getDoubleAt -alignment:hipo::structure::putDoubleAt +alignment:hipo::structure::getLongAt +alignment:hipo::structure::getStringAt + alignment:hipo::structure::putIntAt +alignment:hipo::structure::putShortAt +alignment:hipo::structure::putByteAt +alignment:hipo::structure::putFloatAt +alignment:hipo::structure::putDoubleAt +alignment:hipo::structure::putLongAt +alignment:hipo::structure::putStringAt diff --git a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h index 84069f02..fb87f499 100644 --- a/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h +++ b/src/iguana/algorithms/clas12/PhotonGBTFilter/Algorithm.h @@ -38,7 +38,7 @@ namespace iguana::clas12 { void Run(hipo::banklist& banks) const override; void Stop() override; - /// **Method**: Applies forward detector cut using REC::Particle Theta + /// Applies forward detector cut using REC::Particle Theta /// @param theta lab angle of the particle with respect to the beam direction (radians) /// @returns `true` if the particle's theta is within the forward detector coverage, `false` otherwise bool ForwardDetectorFilter(float const theta) const; @@ -66,14 +66,14 @@ namespace iguana::clas12 { double ecout_m2v = 0; }; - /// **Method**: Applies pid purity cuts to photons, compatible to how the GBT models are trained + /// Applies pid purity cuts to photons, compatible to how the GBT models are trained /// @param E energy of the photon /// @param Epcal energy the photon has deposited in the pre-shower calorimeter /// @param theta lab angle of the photon with respect to the beam direction (radians) /// @returns `true` if the photon passes the pid purity cuts, `false` otherwise bool PidPurityPhotonFilter(float const E, float const Epcal, float const theta) const; - /// **Action function**: Classifies the photon for a given event as signal or background + /// Classifies the photon for a given event as signal or background /// @param particleBank the REC::Particle hipo bank /// @param caloBank the REC::Calorimeter hipo bank /// @param calo_map the std::map<> of calorimeter data for the event, indexed by pindex @@ -83,32 +83,32 @@ namespace iguana::clas12 { bool Filter(hipo::bank const &particleBank, hipo::bank const &caloBank, std::map calo_map, int const row, int const runnum) const; - /// **Method**: Calls the appropriate CatBoost model for the given run group, classifying the photon of interest + /// Calls the appropriate CatBoost model for the given run group, classifying the photon of interest /// @param input_data the input features of the model /// @param runnum the run number associated to the event /// @returns `true` if the bool ClassifyPhoton(std::vector const &input_data, int const runnum) const; - /// **Method**: Gets calorimeter data for particles in the event + /// Gets calorimeter data for particles in the event /// @param bank the bank to get data from /// @returns a map with keys as particle indices (pindex) and values as calo_row_data structs std::map GetCaloMap(hipo::bank const &bank) const; - /// **Method**: Gets the calorimeter vector for a particle in the event + /// Gets the calorimeter vector for a particle in the event /// @param crd data struct of a single REC::Calorimeter's row data /// @returns a ROOT::Math::XYZVector with the coordinates of the particle in the calorimeter ROOT::Math::XYZVector GetParticleCaloVector(PhotonGBTFilter::calo_row_data calo_row) const; - /// **Method**: Gets the mass of a particle given its PID + /// Gets the mass of a particle given its PID /// @param pid the particle ID to get the mass for /// @returns the mass of the particle in GeV; returns -1.0 if the PID is not recognized double GetMass(int pid) const; - /// **Method**: Gets the model function for the run number + /// Gets the model function for the run number /// @param runnum the run of the associated event /// @returns GBT function for the run period std::function const &)> getModelFunction(int runnum) const; diff --git a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h index 90750d40..00813d8f 100644 --- a/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h +++ b/src/iguana/algorithms/example/ExampleAlgorithm/Algorithm.h @@ -83,7 +83,7 @@ namespace iguana::example { // # - `Transform` for a transformation type algorithm, such as momentum corrections // # - `Create` for a creation type algorithm, such as inclusive kinematic (x, Q2, etc.) reconstruction // ############################################################################ - /// **Action function**: checks if the PDG `pid` is positive; + /// @action_function{scalar filter} checks if the PDG `pid` is positive; /// this is an example action function, please replace it with your own /// @param pid the particle PDG to check /// @returns `true` if `pid` is positive diff --git a/src/iguana/tests/meson.build b/src/iguana/tests/meson.build index 9461415d..cb7eeca8 100644 --- a/src/iguana/tests/meson.build +++ b/src/iguana/tests/meson.build @@ -57,31 +57,33 @@ foreach algo : algo_dict ) # multithreaded tests - foreach concurrency_model : [ 'memoize' ] # note: we used to have more, so leave this array in case we want more - multithreading_args = [ - 'multithreading', - '-j', get_option('test_multithreading').to_string(), - '-m', concurrency_model, - '-V', # vary run number - ] - test( - '-'.join(['multithreading', concurrency_model, test_name_algo]), - test_exe, - suite: [ 'algorithm', 'multithreading', concurrency_model ], - args: multithreading_args + [ '-n', get_option('test_num_events') ] + test_args, - is_parallel: false, - env: project_test_env, - timeout: 0, - ) - benchmark( - '-'.join(['benchmark', f'multithreading_@concurrency_model@', test_name_algo]), - test_exe, - suite: [ 'algorithm', 'multithreading', concurrency_model ], - args: multithreading_args + [ '-n', '0' ] + test_args, # benchmark all the events - env: project_test_env, - timeout: 0, - ) - endforeach + if get_option('z_test_multithreading') + foreach concurrency_model : [ 'memoize' ] # note: we used to have more, so leave this array in case we want more + multithreading_args = [ + 'multithreading', + '-j', get_option('test_num_threads').to_string(), + '-m', concurrency_model, + '-V', # vary run number + ] + test( + '-'.join(['multithreading', concurrency_model, test_name_algo]), + test_exe, + suite: [ 'algorithm', 'multithreading', concurrency_model ], + args: multithreading_args + [ '-n', get_option('test_num_events') ] + test_args, + is_parallel: false, + env: project_test_env, + timeout: 0, + ) + benchmark( + '-'.join(['benchmark', f'multithreading_@concurrency_model@', test_name_algo]), + test_exe, + suite: [ 'algorithm', 'multithreading', concurrency_model ], + args: multithreading_args + [ '-n', '0' ] + test_args, # benchmark all the events + env: project_test_env, + timeout: 0, + ) + endforeach + endif endif