-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[Coverage] MCDC: Move findIndependencePairs deferred into MCDCRecord #121188
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
Conversation
@llvm/pr-subscribers-pgo Author: NAKAMURA Takumi (chapuni) ChangesFull diff: https://github.com/llvm/llvm-project/pull/121188.diff 2 Files Affected:
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42da188fef34ee..4f28f5da6cf81f 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -35,6 +35,7 @@
#include <cstdint>
#include <iterator>
#include <memory>
+#include <optional>
#include <sstream>
#include <string>
#include <system_error>
@@ -451,19 +452,22 @@ struct MCDCRecord {
private:
CounterMappingRegion Region;
TestVectors TV;
- TVPairMap IndependencePairs;
+ std::optional<TVPairMap> IndependencePairs;
BoolVector Folded;
CondIDMap PosToID;
LineColPairMap CondLoc;
public:
MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV,
- TVPairMap &&IndependencePairs, BoolVector &&Folded,
- CondIDMap &&PosToID, LineColPairMap &&CondLoc)
- : Region(Region), TV(std::move(TV)),
- IndependencePairs(std::move(IndependencePairs)),
- Folded(std::move(Folded)), PosToID(std::move(PosToID)),
- CondLoc(std::move(CondLoc)){};
+ BoolVector &&Folded, CondIDMap &&PosToID, LineColPairMap &&CondLoc)
+ : Region(Region), TV(std::move(TV)), Folded(std::move(Folded)),
+ PosToID(std::move(PosToID)), CondLoc(std::move(CondLoc)) {
+ findIndependencePairs();
+ }
+
+ // Compare executed test vectors against each other to find an independence
+ // pairs for each condition. This processing takes the most time.
+ void findIndependencePairs();
const CounterMappingRegion &getDecisionRegion() const { return Region; }
unsigned getNumConditions() const {
@@ -494,10 +498,10 @@ struct MCDCRecord {
/// TestVectors requires a translation from a ordinal position to actual
/// condition ID. This is done via PosToID[].
bool isConditionIndependencePairCovered(unsigned Condition) const {
+ assert(IndependencePairs);
auto It = PosToID.find(Condition);
- if (It != PosToID.end())
- return IndependencePairs.contains(It->second);
- llvm_unreachable("Condition ID without an Ordinal mapping");
+ assert(It != PosToID.end() && "Condition ID without an Ordinal mapping");
+ return IndependencePairs->contains(It->second);
}
/// Return the Independence Pair that covers the given condition. Because
@@ -507,7 +511,8 @@ struct MCDCRecord {
/// via PosToID[].
TVRowPair getConditionIndependencePair(unsigned Condition) {
assert(isConditionIndependencePairCovered(Condition));
- return IndependencePairs[PosToID[Condition]];
+ assert(IndependencePairs);
+ return (*IndependencePairs)[PosToID[Condition]];
}
float getPercentCovered() const {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 87d8bb1bbb79c7..2c7a77bac09328 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -221,6 +221,40 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
return LastPoppedValue;
}
+// Find an independence pair for each condition:
+// - The condition is true in one test and false in the other.
+// - The decision outcome is true one test and false in the other.
+// - All other conditions' values must be equal or marked as "don't care".
+void MCDCRecord::findIndependencePairs() {
+ if (IndependencePairs)
+ return;
+
+ IndependencePairs.emplace();
+
+ unsigned NumTVs = TV.size();
+ // Will be replaced to shorter expr.
+ unsigned TVTrueIdx = std::distance(
+ TV.begin(),
+ std::find_if(TV.begin(), TV.end(),
+ [&](auto I) { return (I.second == MCDCRecord::MCDC_True); })
+
+ );
+ for (unsigned I = TVTrueIdx; I < NumTVs; ++I) {
+ const auto &[A, ACond] = TV[I];
+ assert(ACond == MCDCRecord::MCDC_True);
+ for (unsigned J = 0; J < TVTrueIdx; ++J) {
+ const auto &[B, BCond] = TV[J];
+ assert(BCond == MCDCRecord::MCDC_False);
+ // If the two vectors differ in exactly one condition, ignoring DontCare
+ // conditions, we have found an independence pair.
+ auto AB = A.getDifferences(B);
+ if (AB.count() == 1)
+ IndependencePairs->insert(
+ {AB.find_first(), std::make_pair(J + 1, I + 1)});
+ }
+ }
+}
+
mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs,
int Offset)
: Indices(NextIDs.size()) {
@@ -375,9 +409,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
/// ExecutedTestVectorBitmap.
MCDCRecord::TestVectors &ExecVectors;
- /// Number of False items in ExecVectors
- unsigned NumExecVectorsF;
-
#ifndef NDEBUG
DenseSet<unsigned> TVIdxs;
#endif
@@ -446,34 +477,11 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// Fill ExecVectors order by False items and True items.
// ExecVectors is the alias of ExecVectorsByCond[false], so
// Append ExecVectorsByCond[true] on it.
- NumExecVectorsF = ExecVectors.size();
auto &ExecVectorsT = ExecVectorsByCond[true];
ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
std::make_move_iterator(ExecVectorsT.end()));
}
- // Find an independence pair for each condition:
- // - The condition is true in one test and false in the other.
- // - The decision outcome is true one test and false in the other.
- // - All other conditions' values must be equal or marked as "don't care".
- void findIndependencePairs() {
- unsigned NumTVs = ExecVectors.size();
- for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
- const auto &[A, ACond] = ExecVectors[I];
- assert(ACond == MCDCRecord::MCDC_True);
- for (unsigned J = 0; J < NumExecVectorsF; ++J) {
- const auto &[B, BCond] = ExecVectors[J];
- assert(BCond == MCDCRecord::MCDC_False);
- // If the two vectors differ in exactly one condition, ignoring DontCare
- // conditions, we have found an independence pair.
- auto AB = A.getDifferences(B);
- if (AB.count() == 1)
- IndependencePairs.insert(
- {AB.find_first(), std::make_pair(J + 1, I + 1)});
- }
- }
- }
-
public:
/// Process the MC/DC Record in order to produce a result for a boolean
/// expression. This process includes tracking the conditions that comprise
@@ -509,13 +517,8 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
// Using Profile Bitmap from runtime, mark the executed test vectors.
findExecutedTestVectors();
- // Compare executed test vectors against each other to find an independence
- // pairs for each condition. This processing takes the most time.
- findIndependencePairs();
-
// Record Test vectors, executed vectors, and independence pairs.
- return MCDCRecord(Region, std::move(ExecVectors),
- std::move(IndependencePairs), std::move(Folded),
+ return MCDCRecord(Region, std::move(ExecVectors), std::move(Folded),
std::move(PosToID), std::move(CondLoc));
}
};
|
findIndependencePairs
into MCDCRecord
if (It != PosToID.end()) | ||
return IndependencePairs.contains(It->second); | ||
llvm_unreachable("Condition ID without an Ordinal mapping"); | ||
assert(It != PosToID.end() && "Condition ID without an Ordinal mapping"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this changed to an assert from unreachable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect "satisfies or crash" here? I wanted to eliminate the condition.
@@ -221,6 +221,40 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const { | |||
return LastPoppedValue; | |||
} | |||
|
|||
// Find an independence pair for each condition: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this be a doxygen comment in CoverageMapping.h?
|
||
// Compare executed test vectors against each other to find an independence | ||
// pairs for each condition. This processing takes the most time. | ||
void findIndependencePairs(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make sense to have this actually return the std::optional<TVPairMap>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd make sense since it always flush and reconstruct the map.
|
||
IndependencePairs.emplace(); | ||
|
||
unsigned NumTVs = TV.size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const?
|
||
unsigned NumTVs = TV.size(); | ||
// Will be replaced to shorter expr. | ||
unsigned TVTrueIdx = std::distance( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const?
for (unsigned I = TVTrueIdx; I < NumTVs; ++I) { | ||
const auto &[A, ACond] = TV[I]; | ||
assert(ACond == MCDCRecord::MCDC_True); | ||
for (unsigned J = 0; J < TVTrueIdx; ++J) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I understand correctly, we assume that
- The outer loop handles true conditions
- The inner loop handles false conditions
I think this renaming may be clearer:
// All true test vectors are in the range [FirstTrueTVIdx, NumTVs).
for (unsigned TrueTVIdx = FirstTrueTVIdx; TrueTVIdx < NumTVs; ++TrueTVIdx) {
...
// All false test vectors are in the range [0, FirstTrueTVIdx)
for (unsigned FalseTVIdx = 0; FalseTVIdx < FirstTrueTVIdx; ++ FalseTVIdx) {
...
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this is all code movement. Duh. Perhaps we can address this in a follow-up NFC commit.
// - The decision outcome is true one test and false in the other. | ||
// - All other conditions' values must be equal or marked as "don't care". | ||
void MCDCRecord::findIndependencePairs() { | ||
if (IndependencePairs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug output for something like "independence pairs already computed; not finding anything"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Soft updates" is assumed. It is invalidated if "merging" is executed.
This is all code movement so most my comments are probably irrelevant. This looks fine. |
@@ -507,7 +511,8 @@ struct MCDCRecord { | |||
/// via PosToID[]. | |||
TVRowPair getConditionIndependencePair(unsigned Condition) { | |||
assert(isConditionIndependencePairCovered(Condition)); | |||
return IndependencePairs[PosToID[Condition]]; | |||
assert(IndependencePairs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert is unneeded due to immediate dereference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's redundant since isConditionIndependencePairCovered
checks IndependencePairs
. That said, I want to reconfirm before its use *IndependencePairs
.
The result of "Independence pairs" is not mergeable. This change makes defers re-calculation of "Independence pairs" after merging test vectors.
No apparent behavior changes.