mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[MG_IntegrationTest] (P7): the split poison control says which role fired, not merely that someone did
- ReadChildLog concatenated the child's two role halves and the assertion searched the union, so VerifySplitPoisonOmitted. would have been just as green if the stamp the knob withheld had been the CLIENT's - which is the case it exists to rule out, the mechanism under test being the server-side verb stamp honouring MOBILEGL_PIPE_POISON_OMIT
- kOmittedPairs carries FiresOnTheServer; ReadChildLogHalves keeps Client, Server and the union apart; the split pair now asserts the Fatal in the child's SERVER half under MOBILEGL_BUILD_DISAGGREGATED, the monolith pair keeps the union because it has one role
- measured on both backends: client half 0 Fatal{UnmigratedPipeInput lines, server half 1 each - the union search could not tell them apart
- monolith PoisonOmitted. entries stay green (2/2), split VerifySplitPoisonOmitted. stay green (2/2)
This commit is contained in:
@@ -95,14 +95,23 @@ namespace MGITest {
|
||||
// split control: the server's read_pixels backend call DOES read the pack half through the
|
||||
// accessor, under the server's own stamp, which honours the knob in a verify build
|
||||
// (MG_Backend/MGPipe/PipeInputs.cpp's ServerPoisonOmission).
|
||||
//
|
||||
// AND EACH PAIR SAYS WHICH ROLE HAS TO FIRE (`FiresOnTheServer`), which is the whole point
|
||||
// of the split pair and was not checked at all until P7 wave 3's V1 fix round. The reader
|
||||
// below concatenates the child's two role halves and the assertion searched the union, so
|
||||
// `VerifySplitPoisonOmitted.` would have been just as green if the stamp the knob withheld
|
||||
// had been the CLIENT's - which is the case it exists to rule out, because the mechanism
|
||||
// under test is MG_Backend/MGPipe/PipeInputs.cpp's server-side stamp honouring the knob.
|
||||
// The monolith pair has one role and one log half, so it keeps the union.
|
||||
struct OmittedPair {
|
||||
const char* Verb;
|
||||
const char* Field;
|
||||
const char* EarlierVerbs[2]; // verbs the sequence runs BEFORE this one, which must not trip
|
||||
bool FiresOnTheServer; // the Fatal must be in the child's SERVER half, not merely present
|
||||
};
|
||||
constexpr OmittedPair kOmittedPairs[] = {
|
||||
{"GenerateMipmap", "GetActiveTextureUnit", {"@DrawArrays", "@DrawArrays"}},
|
||||
{"ReadPixels", "GetPixelStoreParameters", {"@DrawArrays", "@GenerateMipmap"}},
|
||||
{"GenerateMipmap", "GetActiveTextureUnit", {"@DrawArrays", "@DrawArrays"}, false},
|
||||
{"ReadPixels", "GetPixelStoreParameters", {"@DrawArrays", "@GenerateMipmap"}, true},
|
||||
};
|
||||
constexpr const char* kFatalPrefix = "Fatal{UnmigratedPipeInput";
|
||||
|
||||
@@ -183,16 +192,31 @@ void main() { o_color = vec4(0.25, 0.5, 0.75, 1.0); }
|
||||
// the fill is the client's and the read is the backend's, and in a split build the
|
||||
// backend runs on the server role's thread. A reader that took the client half alone
|
||||
// would report "the child aborted with no Fatal" for every server-side firing.
|
||||
std::string ReadChildLog() {
|
||||
//
|
||||
// THE HALVES ARE ALSO KEPT APART (P7 wave 3, V1), because "did anyone report this" and
|
||||
// "did the SERVER report this" are different questions and only the first one survives
|
||||
// concatenation. Server is empty in a monolith build, which a caller must read as "there
|
||||
// is no such half" rather than as "the server said nothing".
|
||||
struct ChildLog {
|
||||
std::string Client;
|
||||
std::string Server;
|
||||
std::string All; // Client + Server, the union every role-agnostic assertion wants
|
||||
};
|
||||
|
||||
ChildLog ReadChildLogHalves() {
|
||||
ChildLog log;
|
||||
const std::string base = ChildLogBasePath();
|
||||
if (base.empty()) return {};
|
||||
std::string all = ReadWholeFile(ChildRoleLogPath(base, "client"));
|
||||
if (base.empty()) return log;
|
||||
log.Client = ReadWholeFile(ChildRoleLogPath(base, "client"));
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
all += ReadWholeFile(ChildRoleLogPath(base, "server"));
|
||||
log.Server = ReadWholeFile(ChildRoleLogPath(base, "server"));
|
||||
#endif
|
||||
return all;
|
||||
log.All = log.Client + log.Server;
|
||||
return log;
|
||||
}
|
||||
|
||||
std::string ReadChildLog() { return ReadChildLogHalves().All; }
|
||||
|
||||
class PoisonOmissionScenario : public ScenarioTest {
|
||||
protected:
|
||||
// The sequence under test. Deliberately in this order: the DRAW comes first and must
|
||||
@@ -397,7 +421,8 @@ void main() { o_color = vec4(0.25, 0.5, 0.75, 1.0); }
|
||||
std::string reason;
|
||||
ASSERT_TRUE(RunSequenceInAChildProcess(status, reason)) << reason;
|
||||
|
||||
const std::string childLog = ReadChildLog();
|
||||
const ChildLog halves = ReadChildLogHalves();
|
||||
const std::string& childLog = halves.All;
|
||||
ASSERT_TRUE(WIFSIGNALED(status))
|
||||
<< "with the stamp of " << expectedPair << " omitted, the " << pair->Verb << " in the child "
|
||||
<< "had to read a field its verb never filled and abort. It " << DescribeStatus(status)
|
||||
@@ -415,11 +440,30 @@ void main() { o_color = vec4(0.25, 0.5, 0.75, 1.0); }
|
||||
GTEST_SKIP() << "the abort happened, but the lane set no MOBILEGL_LOG_FILE_PATH, so the "
|
||||
"Fatal's text cannot be read back; the PoisonOmitted. ctest entries set it";
|
||||
}
|
||||
EXPECT_NE(childLog.find(std::string(kFatalPrefix) + ", \"" + expectedPair + "\""),
|
||||
std::string::npos)
|
||||
const std::string expectedFatal = std::string(kFatalPrefix) + ", \"" + expectedPair + "\"";
|
||||
EXPECT_NE(childLog.find(expectedFatal), std::string::npos)
|
||||
<< "the child aborted, but not with Fatal{UnmigratedPipeInput, \"" << expectedPair
|
||||
<< "\"} - that message is the whole diagnostic value of the poison. Child log:\n"
|
||||
<< childLog;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// WHICH ROLE, for the split pair (P7 wave 3, V1). The union above answers "did the
|
||||
// poison fire", which is all the monolith pair can be asked; this pair exists to prove
|
||||
// that the SERVER'S OWN verb stamp honours MOBILEGL_PIPE_POISON_OMIT
|
||||
// (MG_Backend/MGPipe/PipeInputs.cpp's ServerPoisonOmission) - the thing that was NOT
|
||||
// true before wave 3 and made the control silently green. A client-side firing would
|
||||
// satisfy the union and prove the opposite of what the entry claims, so the half is
|
||||
// named here.
|
||||
if (pair->FiresOnTheServer) {
|
||||
EXPECT_NE(halves.Server.find(expectedFatal), std::string::npos)
|
||||
<< "the child aborted with " << expectedFatal << ", but NOT in its server-role log. "
|
||||
"This pair is the split arm's control and its whole claim is that the stamp the "
|
||||
"SERVER writes at the verb boundary honours the omission - a firing anywhere "
|
||||
"else means the withheld stamp was the client's and the server-side half is "
|
||||
"untested. Client half:\n"
|
||||
<< halves.Client << "\nServer half:\n"
|
||||
<< halves.Server;
|
||||
}
|
||||
#endif
|
||||
for (const char* earlier : pair->EarlierVerbs) {
|
||||
EXPECT_EQ(childLog.find(earlier), std::string::npos)
|
||||
<< "a verb that ran BEFORE the omitted one (" << earlier << ") also tripped the "
|
||||
|
||||
@@ -213,6 +213,13 @@ server 半边日志:
|
||||
[mgl-srv-apply/FATAL]: MGPipe: Fatal{UnmigratedPipeInput, "GetPixelStoreParameters@ReadPixels"}
|
||||
```
|
||||
|
||||
**正形条目断言的是「哪个角色」,不是「有没有人」(V1 修复轮补)。** `ReadChildLog()` 把子进程的 client 与 server
|
||||
两个半边连起来,原断言查的是并集——而这一对配对存在的理由恰恰是 **server 自己的 verb stamp 遵守 knob**
|
||||
(`ServerPoisonOmission`),一个 client 侧的触发会同样满足并集、却证明了相反的事。现在 `kOmittedPairs` 每对带
|
||||
`FiresOnTheServer`,split 那一对额外断言 Fatal 出现在**子进程的 server 半边**里。实测两后端:client 半边
|
||||
`Fatal{UnmigratedPipeInput` **0 行**,server 半边**各 1 行**——并集断言此前确实分辨不出来。monolith 那一对只有一个
|
||||
角色,仍查并集。
|
||||
|
||||
正形条目 `VerifySplitCorrupted.` / `VerifySplitReadCorrupted.` / `VerifySplitPoisonOmitted.` 两后端 6/6 绿。
|
||||
|
||||
### 3.2 发现 C:monolith 的 POISON_OMIT 配对在 split 臂上是哑的
|
||||
|
||||
Reference in New Issue
Block a user