-
Notifications
You must be signed in to change notification settings - Fork 444
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
[P4Testgen] Fix behavior of coverage on edge cases with no nodes to cover #4275
Conversation
midend/coverage.h
Outdated
|
||
/// @returns true if and only if at least one of the coverage-collection options (cover*) is | ||
/// enabled | ||
bool coverageEnabled() const { return coverStatements || coverTableEntries; } |
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.
I've opted to add this getter to make it more likely this will be properly updated when new coverage types are added.
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.
Instead, I would add an option to CoverageOptions
that sets this value true, whenever one of the values is set.
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.
I am not sure I understand what you mean. Do you suggest to have a derived boolean argument in the struct? That would seem like needless duplication of information at risk of inconsistency to me.
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.
Yes, set the value here: https://github.com/p4lang/p4c/blob/main/backends/p4tools/modules/testgen/options.cpp#L256
You can easily precompute the boolean value here. It will also automatically pick up any new coverage option that might be added. This way you do not need to hard-code all the possible coverage options in the helper.
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.
I don't like that all that much. The CoverageOptions
struct is not strictly bound to be filled by options only, it is not even defined in the headers that process options. Therefore, having a derived attribute adds an invariant to the class that needs to hold when the class values are modified/set. Having the getter needs an invariant too (that it ORs all the cover*
values), but this one is at least localized to the class itself.
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.
You could also add this flag to the testgen options class instead of the options structure.
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.
OK, let's do it that way. Although I still think having the member function did make sense.
@@ -115,6 +115,14 @@ int Testgen::mainImpl(const IR::P4Program *program) { | |||
if (seed) { | |||
printFeature("test_info", 4, "============ Program seed %1% =============\n", *seed); | |||
} | |||
if (testgenOptions.minCoverage > 0 && !testgenOptions.coverageOptions.coverageEnabled()) { |
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.
This is something I would catch in the options early, if possible.
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.
This seemed quite early to me, but I've now moved it even earlier just after option processing.
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.
Options should be processed as early as possible to get immediate feedback. Otherwise, you run your tests for a couple of minutes then get this error.
We typically validate options already for each lambda we add. For example, here you could throw an error if you want to enable minCoverage without previously enable coverage in some way. This way you also do not require an extra validate call. This requires ordering, but that seems fine to me. This is a limitation of the way our options work.
I am also okay with adding validate
, but not sure how much usage that function call will see.
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.
I don't like requiring one to be set before another, that is why I did not want to put the validation into the lambdas.
midend/coverage.h
Outdated
|
||
/// @returns true if and only if at least one of the coverage-collection options (cover*) is | ||
/// enabled | ||
bool coverageEnabled() const { return coverStatements || coverTableEntries; } |
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.
Instead, I would add an option to CoverageOptions
that sets this value true, whenever one of the values is set.
"It is not allowed to have --assert-min-coverage set to non-zero without a coverage " | ||
"tracking enabled with --track-coverage option. Without coverage tracking, the " | ||
"--assert-min-coverage is meaningless."); | ||
FATAL_ERROR("Incompatible options given."); |
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.
I approved but I do not think this is necessary. We will exist if we encounter an error during processing. If not, that is a bug.
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.
Seems like the check is not early enough and before the compiler context is set it is not possible to check error count either.
tests/empty_1/p4/main.p4:19: fatal error: when writing output to : Broken pipe
19 |
|
compilation terminated.
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.
Hmm that is a little odd, we have been using ::error
just fine in the options classes and the compiler context is set up before the validate call.
The entire way options are handled in P4Testgen is a little funky (there are a bunch of hacks to set up context). So there might be something awry there.
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.
Maybe the exception thrown with FATAL_ERROR causes the problem? We have not tested any exception handling that early.
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.
I think the handler for errors in the option parsing works differently, it also prints the usage if the argument parsing fails. What I was testing (and what produced this weird error) was just having the error
there and no FATAL_ERROR
, so there were no exceptions thrown.
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.
Did this get resolved?
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.
Unless we change error handling during process, the FATAL_ERROR is the best bet to cleanly end the processing (in the compiler, there are only warnings, so this does not matter).
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.
I looked into this, basically we need to do this
if (::errorCount() > 0) {
return std::nullopt;
}
after the validate call to not return a broken compile context. We could also return true/false in validate.
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.
Made it return. ::errorCount()
is not available before the context is set (it could be extracted from the context, but this seems cleaner to me).
bad034d
to
67bc233
Compare
Rebased + using the same name as is used in the |
67bc233
to
d57ba39
Compare
…ing coverable with coverage enabled
Co-authored-by: Fabian Ruffy <[email protected]>
995a62a
to
485812a
Compare
This PR changes behavior of testgen on various edge cases with regard to node coverage:
--track-coverage TABLE_ENTRIES
is enabled (withoutSTATEMENTS
) and there are no tables.--assert-min-coverage
can no longer be enabled unless--track-coverage
is enabled as it does not make sense without anything to cover.============ Test 0 ============
(coverage disabled)============ Test 0: No coverable nodes ============