Repository navigation
Fix #15129: Improve matching performance for hash based suppressions - #8970
Conversation
4f206e4 to
10081d5
Compare
10081d5 to
b7cb7b9
Compare
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
I found no new problems.
The new index (mHashSuppressions / mNonHashSuppressions) holds raw pointers into the std::list mSuppressions. That is safe here for three reasons:
- Elements are only ever appended with
push_back, never erased, so the pointers stay valid. SuppressionListcannot be copied or moved because it has astd::mutexmember, so no copy can end up pointing into another object's list.- Every lookup and change of the index happens while
mSuppressionsSyncis locked.
The new matching gives the same results as before. A hash suppression could only ever match an error with the same hash; for any other error it was marked checked and nothing more. checked is never read for hash suppressions, because all three getUnmatched*Suppressions skip hash > 0, so skipping them changes nothing. isSuppressed still checks every candidate and marks all of them matched. isSuppressedExplicitly still stops at the first match, which only changes which suppression gets marked matched, and that has no visible effect.
The ProcessExecutor change is right. Suppression::toString() leaves out the hash, so before this PR the parent rebuilt a checked hash suppression from the child as a suppression without a hash, which is a broader suppression than the user wrote.
Testing
- Built
cppcheckandtestrunnerinpr/withmake -j8, without errors. ./testrunner TestSuppressions TestProcessExecutor TestThreadExecutor TestSingleExecutor: 71 tests, 0 failed.pytest other_test.py -k "ipc or suppr": 23 passed, including the newtest_ipc_hash_suppressions.pytest inline-suppress_test.py: 26 passed, 7 skipped, 1 xfailed.
Manual tests in scratch/:
- Executors agree: four files, each
void fN() { int x = 1; int yN = 2; }, checked with--suppress-xmlholding oneunreadVariablesuppression that has a hash and no fileName.-j1,-j2 --executor=processand-j2 --executor=threadeach reported 7unreadVariable(8 minus the suppressed one), so all three executors give the same result. - Large baseline: a file with 50,000 hash suppressions plus the real one, run on 3 files. It finished in about 0.25 s single-threaded and about 0.33 s with
-j2 --executor=process, with the correct results. - Duplicates: two identical hash suppressions in the XML are still rejected with
suppression 'unreadVariable' already exists.
I did not build base/, so I have no timing from before the PR to compare with.
Automated review of b7cb7b9 by Claude. The pull request was built and tested locally.
Makes it so that hash based suppressions are indexed by hash.
Matching hash based suppressions is now O(1) (ignoring collisions) instead of O(n).
For large code bases using baseline suppressions (which may be in the number of tens of thousands) this leads to a substantial speed up. We could probably speed up matching of other suppressions in the future as well, but I assume these are in general manually added and won't even get close to the same number as baseline suppressions. Also fixed a bug in ProcessExecutor that would cause new suppressions to be added unintentionally.