Skip to content

Conversation

@vepadulano
Copy link
Member

@vepadulano vepadulano commented Oct 29, 2025

This PR collects the fixes and correlated testing in the latest campaign to fix the CMS DAS MiniAOD analysis framework, the only MiniAOD analysis system supported by the CMS Common Analysis Tools group (see https://indico.cern.ch/event/1330797/papers/5796853/files/13266-CAT_ACAT24_proceeding.pdf)

@vepadulano vepadulano added this to the 6.38.00 milestone Oct 29, 2025
@vepadulano vepadulano self-assigned this Oct 29, 2025
@vepadulano vepadulano added in:TTree experiment Affects an experiment / reported by its software & computimng experts labels Oct 29, 2025
@github-actions
Copy link

github-actions bot commented Oct 29, 2025

Test Results

    22 files      22 suites   3d 19h 24m 43s ⏱️
 3 707 tests  3 707 ✅ 0 💤 0 ❌
79 603 runs  79 603 ✅ 0 💤 0 ❌

Results for commit aacd4c1.

♻️ This comment has been updated with latest results.

@vepadulano vepadulano changed the title [tree] Forward friend tree update notification to all external friends Fixes for TTree with complex friend hierarchies Oct 29, 2025
@vepadulano
Copy link
Member Author

This PR now
Fixes #20226
Fixes #20228

See the related commits

Copy link
Collaborator

@ferdymercury ferdymercury left a comment

Choose a reason for hiding this comment

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

Thanks a lot!

Some mini-observations:

  • There are more places where fixing the potential integer overflow is advisable, see https://github.com/root-project/root/pull/20227/files, in TTreePlayer, but also in TSpider, TChain
  • precalculating lastentry is already being used in three other places in the ROOT tree code, so the current solution (entry - firstentry < nentries), while it works perfectly, is a bit less homogeneous with the existing than my proposal (entry <= lastentry)

@vepadulano
Copy link
Member Author

There are more places where fixing the potential integer overflow is advisable, see https://github.com/root-project/root/pull/20227/files, in TTreePlayer, but also in TSpider, TChain

Thanks for pointing these out! I acknowledge there may be more places to fix. For each of those, we need a corresponding reproducer that fails without the fix and works with the fix. For now those places are not interfering immediately with the code changes needed for this PR, so I would in principle tackle them separately. I'm still developing more tests offline which will end up in this PR. If while developing those tests I see that some other integer overflow is the problem, then I will create the corresponding issue+commit in this PR.

precalculating lastentry is already being used in three other places in the ROOT tree code

Where exactly? I can only see in TChain::Loop in a dead code section (preceded by #if 0). There is another instance in tree/treeplayer, but there the way it's calculated is not trivially applicable to the two int overflow fixes added in this PR.

@ferdymercury
Copy link
Collaborator

ferdymercury commented Oct 29, 2025

For each of those, we need a corresponding reproducer that fails without the fix and works with the fix. For now those places are not interfering immediately with the code changes needed for this PR, so I would in principle tackle them separately.

Thanks, got it. An easy failures-reproducer of two of the locations: TTreeplayer lines 237 and 620:

change line 83 of tutorials/io/tree/tree109_friend.C with
auto TF = T->CopyTree("z<10", 0, TTree::kMaxEntries, 2);
and you'll get an integer overflow. It affects both locations/functions of TTreePlayer. (One should not need to know how many entries the tree has in total even if he wants to skip a few from the beginning).

(For the other locations I do not have a repro.)

@vepadulano vepadulano force-pushed the gh-20033 branch 2 times, most recently from 97a4b1e to 68c8968 Compare October 30, 2025 09:23
@vepadulano
Copy link
Member Author

vepadulano commented Oct 31, 2025

@pcanal I addressed all your comments. I also added in the last commit an extension to one of the testing suites that I introduced in an earlier commit, now it considers all cases in which a call to TChain::Scan is accessing one of the friend chains with a name of chain that may be different than the name of tree it holds. ATOW, this PR introduces the following amount of tests:

gh20033.cxx

586: [----------] Global test environment tear-down
586: [==========] 4080 tests from 3 test suites ran. (17421 ms total)
586: [  PASSED  ] 4064 tests.
586: [  SKIPPED ] 16 tests, listed below:

regressions.cxx

589: [----------] 3 tests from TTreeScan (4 ms total)
589: 
589: [----------] 1 test from TTreeDraw (0 ms total)

Copy link
Member

@pcanal pcanal left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks.

@vepadulano
Copy link
Member Author

As discussed privately with @pcanal, I have reorganised the commit history of this PR to have all the code changes at the beginning, and separate every type of new test scenario added in a different commit, appended after the changes. Another PR has been opened just with the test commits to see the failures in isolation --> #20263

@vepadulano vepadulano added the test coverage Run the test code coverage workflow on this PR label Oct 31, 2025
@vepadulano vepadulano closed this Oct 31, 2025
@vepadulano vepadulano reopened this Oct 31, 2025
@vepadulano
Copy link
Member Author

Pasting here errors from the tests seen in the other PR.

Regression tests

[ RUN      ] TTreeScan.IntOverflow
File <tree_20226_regression_redirect.txt> created
/github/home/ROOT-CI/src/tree/treeplayer/test/regressions.cxx:396: Failure
Expected equality of these values:
  redirectOutput.str()
    Which is: "************************\n*    Row   *       val *\n************************\n*        3 *         3 *\n************************\n"
  expectedScanOut
    Which is: "************************\n*    Row   *       val *\n************************\n*        3 *         3 *\n*        4 *         4 *\n*        5 *         5 *\n*        6 *         6 *\n*        7 *         7 *\n*        8 *         8 *\n*        9 *         9 *\n************************\n"
With diff:
@@ +3,9 @@
 ************************
 *        3 *         3 *
+*        4 *         4 *
+*        5 *         5 *
+*        6 *         6 *
+*        7 *         7 *
+*        8 *         8 *
+*        9 *         9 *
 ************************\n


[  FAILED  ] TTreeScan.IntOverflow (56 ms)
[ RUN      ] TTreeScan.chainNameWithDifferentTreeName
/github/home/ROOT-CI/src/tree/treeplayer/test/regressions.cxx:457: Failure
Expected: (c.FindBranch("differentNameForChain.val")) != (nullptr), actual: NULL vs (nullptr)

[  FAILED  ] TTreeScan.chainNameWithDifferentTreeName (2 ms)
[ RUN      ] TTreeScan.TTreeGetBranchOfFriendTChain
/github/home/ROOT-CI/src/tree/treeplayer/test/regressions.cxx:536: Failure
Expected: (tree1->FindBranch("stepzerochain.value")) != (nullptr), actual: NULL vs (nullptr)

[  FAILED  ] TTreeScan.TTreeGetBranchOfFriendTChain (3 ms)
[----------] 3 tests from TTreeScan (63 ms total)

[----------] 1 test from TTreeDraw
[ RUN      ] TTreeDraw.IntOverflow
/github/home/ROOT-CI/src/tree/treeplayer/test/regressions.cxx:430: Failure
Expected equality of these values:
  nEntriesSelected
    Which is: 1
  7

New tests for complex friendship hierarchies scenarios

1500/3660 Test  #672: gtest-tree-treeplayer-treeplayer-gh20033 ..........................................................***Failed    0.61 sec
Running main() from /builddir/build/BUILD/googletest-1.14.0/googletest/src/gtest_main.cc
[==========] Running 4080 tests from 3 test suites.
[----------] Global test environment set-up.
[----------] 176 tests from Run/GH20033Regression
[ RUN      ] Run/GH20033Regression.Test/StepOneTTree_StepTwoTTree_StepThreeTTree_StepFourTTree_0
/github/home/ROOT-CI/src/core/testsupport/src/TestSupport.cxx:93: Failure
Failed
Received unexpected diagnostic of severity 4000 at 'TUnixSystem::DispatchSignals' reading 'segmentation violation'.
Suppress those using ROOT/TestSupport.hxx

 Generating stack trace...
 0x00007f5ab1fbab12 in TTreePlayer::Scan(char const*, char const*, char const*, long long, long long) at /github/home/ROOT-CI/src/tree/treeplayer/src/TTreePlayer.cxx:2774 (discriminator 2) from /github/home/ROOT-CI/build/lib/libTreePlayer.so
 0x000000000041c4b6 in GH20033Regression_Test_Test::TestBody() at /github/home/ROOT-CI/src/tree/treeplayer/test/gh20033.cxx:396 from /github/home/ROOT-CI/build/tree/treeplayer/test/treeplayer_gh20033
 0x00007f5ab0bbca02 in <unknown> from /lib64/libgtest.so.1.14.0
 0x00007f5ab0ba7996 in testing::Test::Run() + 0xd6 from /lib64/libgtest.so.1.14.0
 0x00007f5ab0ba7b95 in testing::TestInfo::Run() + 0x1d5 from /lib64/libgtest.so.1.14.0
 0x00007f5ab0ba7d9f in testing::TestSuite::Run() + 0x1bf from /lib64/libgtest.so.1.14.0
 0x00007f5ab0bb41d0 in testing::internal::UnitTestImpl::RunAllTests() + 0x340 from /lib64/libgtest.so.1.14.0
 0x00007f5ab0bb4808 in testing::UnitTest::Run() + 0x138 from /lib64/libgtest.so.1.14.0
 0x00007f5ab1ed5114 in main + 0x44 from /lib64/libgtest_main.so.1.14.0
 0x00007f5ab0122348 in <unknown> from /lib64/libc.so.6
 0x00007f5ab012240b in __libc_start_main at :? from /lib64/libc.so.6
 0x0000000000418205 in _start + 0x25 from /github/home/ROOT-CI/build/tree/treeplayer/test/treeplayer_gh20033
CMake Error at /github/home/ROOT-CI/src/cmake/modules/RootTestDriver.cmake:232 (message):
  error code: 139

@vepadulano
Copy link
Member Author

Here is a link to the test runs in the other PR https://github.com/root-project/root/actions/runs/18983943721?pr=20263

@codecov
Copy link

codecov bot commented Oct 31, 2025

Codecov Report

❌ Patch coverage is 53.42466% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 34.96%. Comparing base (56be091) to head (aacd4c1).
⚠️ Report is 13 commits behind head on master.

Files with missing lines Patch % Lines
tree/tree/src/TTree.cxx 51.42% 0 Missing and 17 partials ⚠️
tree/tree/src/TChain.cxx 55.55% 5 Missing and 11 partials ⚠️
tree/treeplayer/src/TTreePlayer.cxx 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #20222      +/-   ##
==========================================
- Coverage   34.98%   34.96%   -0.03%     
==========================================
  Files        3391     3392       +1     
  Lines      493265   493394     +129     
  Branches   243723   243756      +33     
==========================================
- Hits       172547   172493      -54     
- Misses     207301   207558     +257     
+ Partials   113417   113343      -74     
Flag Coverage Δ
unittests 34.96% <53.42%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@pcanal pcanal left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks.

TTree::FindBranch already took into account the case of the user wanting to find a branch in the tree by preceding the branch name with the tree name itself. The same logic was not applied symmetrically in TChain::FindBranch, so it's now introduced. The logic is written such that it only performs a copy of the lookup string after having checked that it starts with the name of the chain itself followed by a dot.
TTree::FindLeaf already took into account the case of the user wanting to find a leaf in the tree by preceding the branch name with the tree name itself. The same logic was not applied symmetrically in TChain::FindLeaf, so it's now introduced. The logic is written such that it only performs a copy of the lookup string after having checked that it starts with the name of the chain itself followed by a dot.
The general idea for this test suite is to have one single source of data, a TChain, that is befriended by a long enough friendship hierarchy, namely four consecutive layers of friends. The outermost dataset is the one that drives the event loop, either via SetBranchAddress + raw loop or via TTree::Scan. The data comes from the innermost TChain. All the combinations of TTree/TChain at the various steps of the hierarchy are tried. Furthermore, TTree::Scan is called with an increasingly larger starting entry to ensure that even when starting e.g. from an entry of the second tree of the innermost chain the Scan works well.
Add a test suite for the scenario of multiple levels of friendship hierarchy where all TTree/TChain datasets in the hierarchy have a branch with exactly the same name. Call TTree::Scan and make sure that the correct branch from the correct TTree is accessed with every possible combination of using TTree/TChain to steer the execution or only one or more of the branches of the hierarchy. This scenario represents the use case of comparing the same quantity which can pass through various derivation steps and each step must be compared with the other ones.
Introduce a test with a long friendship hierarchy where data is accessed via TTree::Scan. Every dataset in the hierarchy has the same branch name. The Scan expression uses different branch names from every dataset in the same component of the expression. This checks that the branch addresses are properly set and they don't get mixed up.
Tests that a TChain with a name different than its inner TTree can find a branch of the TTree when the user passes a branch lookup string of the form "chainName.branchName".
Tests that a TTree that has a TChain friend can retrieve a branch from the inner TTree of the friend TChain by prefixing the branch name with the chain name, even if the inner TTree of the friend TChain might have a different name than the chain name.
@vepadulano
Copy link
Member Author

The latest force-push is just to introduce a small improvement. In TChain::FindBranch and TChain::FindLeaf we don't need the copy of the std::string_view to ensure the character array is null-terminated. That's because we're only truncating from the beginning of the view (removing the leading chainName. part), and not from the end. The input const char * into the function is null-terminated already.

@dpiparo dpiparo merged commit 8bb872c into root-project:master Nov 2, 2025
28 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

experiment Affects an experiment / reported by its software & computimng experts in:TTree test coverage Run the test code coverage workflow on this PR

Projects

None yet

4 participants