mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Test] (P11 M2): dev's two Magma scenarios on the split arms - both on Espryt's three arms, OversizedRecordingSplitScenario on Magma's three (and pinned to a 64-draw budget on split and spawn, where the server reads it), DescriptorPoolGrowthScenario's census cases on Magma's split arm only; the split-recording arming reads both role logs and dev's pinned lane holds its log's RESOURCE_LOCK, and the census cases count the sets the wire arm holds between its descriptor rewinds
This commit is contained in:
@@ -1068,6 +1068,11 @@ gtest_discover_tests(MobileGLIntegrationTest
|
||||
# renderer's latched MGLOG_I) proves the split happened at all - on a renderer that records the
|
||||
# whole frame into one command buffer, it is the assertion that goes red. DirectVulkan only:
|
||||
# the budget steers nothing on DirectGLES, whose driver flushes on its own.
|
||||
#
|
||||
# P11 M2: RESOURCE_LOCK, for the UnlocatedIoBlocks lane's reason above - EVERY case here reads the
|
||||
# lane's one log back, and the library truncates it at each process's start, so under `ctest -j` a
|
||||
# sibling case wipes the line a reading case is looking for (measured on this tree: 5 of 8 red at
|
||||
# -j 6, a different five on the monolith and inproc runs).
|
||||
gtest_discover_tests(MobileGLIntegrationTest
|
||||
TEST_PREFIX "DirectVulkan.SplitRecording."
|
||||
TEST_FILTER "OversizedRecordingSplitScenario.*"
|
||||
@@ -1075,6 +1080,7 @@ gtest_discover_tests(MobileGLIntegrationTest
|
||||
PROPERTIES
|
||||
LABELS integration-gpu
|
||||
TIMEOUT ${MGL_ITEST_TIMEOUT}
|
||||
RESOURCE_LOCK oversized-recording-split.log
|
||||
ENVIRONMENT "${MGL_ITEST_VULKAN_SPLIT_RECORDING_ENVIRONMENT}"
|
||||
)
|
||||
|
||||
@@ -2870,6 +2876,18 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
|
||||
mgl_itest_register_split_arms("ImageBindableRemintScenario.*" "")
|
||||
mgl_itest_register_split_arms("PartialUploadOverGpuContentScenario.*" "")
|
||||
|
||||
# ---- P11 M2: DEV'S TWO MAGMA SCENARIOS ON THE SPLIT ARMS ---------------------------------
|
||||
#
|
||||
# Merged from dev@c14283ee with their monolith entries. Both are plain GL and check pixels on
|
||||
# every backend: OversizedRecordingSplitScenario draws frames whose state spans a command-buffer
|
||||
# split (d20c2d01), DescriptorPoolGrowthScenario draws a 4096-distinct-set frame and gives it
|
||||
# back (c2de6576/53fa16c2). On Espryt neither has anything else to check - the draw budget and
|
||||
# the pool census are Magma's - so every case runs on all three arms. The Magma arms are laid by
|
||||
# hand below (`DirectVulkan.<arm>.Oversized.`, `.SplitRecording64.`, `DirectVulkan.Split.DescPool.`),
|
||||
# where the gated flavour and the per-arm exceptions live.
|
||||
mgl_itest_register_split_arms("OversizedRecordingSplitScenario.*" "")
|
||||
mgl_itest_register_split_arms("DescriptorPoolGrowthScenario.*" "")
|
||||
|
||||
# ---- P5b t2: the transform-feedback spans, the XFB object bind, the patch parameter -------
|
||||
#
|
||||
# MG_Remote/CONTRACT-P5B.md §2 t2. The three P5 lanes above are the REDUCED PATH's targets
|
||||
@@ -3923,6 +3941,80 @@ if (MOBILEGL_BUILD_DISAGGREGATED)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# P11 M2: DEV'S TWO MAGMA SCENARIOS ON MAGMA'S ARMS, GATED, in the band flavour. Every entry gets a
|
||||
# private log through MGL_SPLIT_ARM_TEST_LISTS.
|
||||
#
|
||||
# Oversized. OversizedRecordingSplitScenario under the default draw budget (16384), all three
|
||||
# arms: every case's pixels, unsplit - dev's control. Its arming is not checked here (no
|
||||
# budget pinned).
|
||||
# SplitRecording64. The same cases with MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER=64, so every
|
||||
# case splits (d20c2d01's SplitOversizedRecording, which runs ahead of the wire arm's draw and
|
||||
# dispatch too) and asserts the renderer's latched MGLOG_I. SPLIT AND SPAWN ONLY, one entry per
|
||||
# case. The budget and the log line are the SERVER renderer's - the apply thread inproc, the
|
||||
# spawned server (which copies this entry's environment, log base included) under spawn - and
|
||||
# the scenario reads both role logs of its base (PipeStatsWindow). The tcp arm's server is
|
||||
# the lane fixture, which no per-entry property reaches: a tcp copy would run the default
|
||||
# budget under a name claiming 64 and its arming would find nothing (spawn_lane_parity.py,
|
||||
# MAGMA_SERVER_ENV_KNOB_NO_TCP). The line is latched once per process, hence one per case.
|
||||
# DescPool. DescriptorPoolGrowthScenario, SPLIT ONLY. Both cases read the pool census
|
||||
# (DirectVulkan::GetDescriptorPoolCensus), which is in-process: inproc it is taken on the
|
||||
# apply thread (the test probe, between drain batches); on spawn and tcp the pools live in the
|
||||
# server process and the census answers unavailable, so a copy there would check pixels
|
||||
# under a name claiming the pools (spawn_lane_parity.py, MAGMA_INPROC_ONLY). Those pixels run
|
||||
# on every arm in the Espryt entries above and in the Magma informational and full-suite tiers.
|
||||
if (MOBILEGL_BUILD_DISAGGREGATED)
|
||||
set(MGL_ITEST_OVERSIZED_CASES
|
||||
EveryDrawOfTheFrameLandsAcrossCommandBufferSplits
|
||||
ADepthOccluderDrawnBeforeTheSplitHidesADrawAfterIt
|
||||
AStencilMarkMadeBeforeTheSplitGatesADrawAfterIt
|
||||
BlendingAccumulatesOntoPixelsWrittenBeforeTheSplit
|
||||
AMultisampleTargetKeepsItsSamplesAcrossTheSplit
|
||||
OcclusionQueriesOpenAcrossTheSplitCountBothSides
|
||||
APrimitivesGeneratedQueryOpenAcrossTheSplitCountsBothSides
|
||||
ATransformFeedbackCaptureActiveAcrossTheSplitAppendsEveryDraw)
|
||||
foreach(mglItestArm IN LISTS MGL_ITEST_MAGMA_ARMS)
|
||||
mgl_itest_magma_arm_shape(${mglItestArm})
|
||||
mgl_itest_join_environment(mglItestMagmaM2Environment
|
||||
${MGL_ITEST_MAGMA_BAND_FLAVOUR_ENV} ${mglItestArmTransportEnv})
|
||||
gtest_discover_tests(MobileGLIntegrationTest
|
||||
TEST_PREFIX "DirectVulkan.${mglItestArm}.Oversized."
|
||||
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
|
||||
TEST_FILTER "OversizedRecordingSplitScenario.*"
|
||||
DISCOVERY_TIMEOUT 30
|
||||
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
|
||||
${mglItestArmProperties}
|
||||
ENVIRONMENT "${mglItestMagmaM2Environment}")
|
||||
list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}")
|
||||
math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1")
|
||||
if(NOT mglItestArm STREQUAL "Tcp")
|
||||
foreach(mglItestOversizedCase IN LISTS MGL_ITEST_OVERSIZED_CASES)
|
||||
gtest_discover_tests(MobileGLIntegrationTest
|
||||
TEST_PREFIX "DirectVulkan.${mglItestArm}.SplitRecording64."
|
||||
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
|
||||
TEST_FILTER "OversizedRecordingSplitScenario.${mglItestOversizedCase}"
|
||||
DISCOVERY_TIMEOUT 30
|
||||
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
|
||||
${mglItestArmProperties}
|
||||
ENVIRONMENT "${mglItestMagmaM2Environment}\;MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER=64")
|
||||
list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}")
|
||||
math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1")
|
||||
endforeach()
|
||||
endif()
|
||||
if(mglItestArm STREQUAL "Split")
|
||||
gtest_discover_tests(MobileGLIntegrationTest
|
||||
TEST_PREFIX "DirectVulkan.Split.DescPool."
|
||||
TEST_LIST "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}"
|
||||
TEST_FILTER "DescriptorPoolGrowthScenario.*"
|
||||
DISCOVERY_TIMEOUT 30
|
||||
PROPERTIES LABELS "${mglItestMagmaLabels}" TIMEOUT ${MGL_ITEST_TIMEOUT}
|
||||
${mglItestArmProperties}
|
||||
ENVIRONMENT "${mglItestMagmaM2Environment}")
|
||||
list(APPEND MGL_SPLIT_ARM_TEST_LISTS "MGL_SPLIT_ARM_TESTS_${MGL_SPLIT_ARM_INDEX}")
|
||||
math(EXPR MGL_SPLIT_ARM_INDEX "${MGL_SPLIT_ARM_INDEX} + 1")
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# P10 B: ASYNC COMPILATION, THE XFB QUERY PAIR AND GL_PRIMITIVES_GENERATED ON MAGMA, all three
|
||||
# arms, GATED, in the band flavour (role-split state, strict errors, run-ahead). The DirectGLES
|
||||
# half of the first two is registered beside the other Espryt arms; the third is Magma's alone.
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "../Harness/HeadlessGL.h"
|
||||
#include "../Harness/ScenarioFixture.h"
|
||||
#include "../Harness/SplitRuntimePeek.h"
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#include <MG_Backend/DirectVulkan/DescriptorPoolCensus.h>
|
||||
@@ -97,6 +98,20 @@ void main() { o_color = texture(uTex, vec2(0.5)); }
|
||||
return (end != nullptr && *end == '\0') ? parsed : fallback;
|
||||
}
|
||||
|
||||
// P11 M2: HOW MANY OF THE BURST'S SETS ONE FRAME SLOT HOLDS AT ONCE. All kDraws of them on
|
||||
// the monolith arm. Under a split transport the server draws through the WIRE arm, which
|
||||
// rewinds a slot's set cursors every UniformManager::kWireDescriptorSetBudget (2048) sets once
|
||||
// it has proved the GPU done with them (VulkanRenderer::RewindWireDescriptorSetsIfDue), so its
|
||||
// cache holds the burst 2048 sets at a time: the burst still needs a set per draw, grows the
|
||||
// slot geometrically to that and is given back by the same trim, only the census counts the
|
||||
// sets held rather than the draws. (The census itself is in-process - inproc it is read on the
|
||||
// server's apply thread; spawn and tcp answer unavailable - see GetDescriptorPoolCensus.)
|
||||
constexpr std::uint64_t kWireDescriptorSetBudget = 2048;
|
||||
std::uint64_t BurstSetsHeldAtOnce() {
|
||||
const std::uint64_t draws = static_cast<std::uint64_t>(kDraws);
|
||||
return PeekSplitRuntime().transportResolved ? std::min(draws, kWireDescriptorSetBudget) : draws;
|
||||
}
|
||||
|
||||
// Pools a geometric policy adds for n sets from an empty flavour: 64, 128, ... up to the cap,
|
||||
// then one per cap. The old first-pool rule needed n/128 or n/256 of them.
|
||||
std::uint64_t GeometricPoolBound(std::uint64_t n) {
|
||||
@@ -269,15 +284,16 @@ void main() { o_color = texture(uTex, vec2(0.5)); }
|
||||
if (!IsVulkan() || !after.available) return;
|
||||
// Falsifiability first: had the renderer's memos collapsed the draws onto shared sets, the
|
||||
// slot would never have needed to grow and the bound below would pass on any policy.
|
||||
ASSERT_GE(after.cachedSets, before.cachedSets + kDraws)
|
||||
const std::uint64_t held = BurstSetsHeldAtOnce();
|
||||
ASSERT_GE(after.cachedSets, before.cachedSets + held)
|
||||
<< "the frame did not allocate one descriptor set per draw, so it does not exercise growth. Before: "
|
||||
<< Describe(before) << "; after: " << Describe(after);
|
||||
const std::uint64_t added = after.pools - before.pools;
|
||||
RecordProperty("census_before", Describe(before));
|
||||
RecordProperty("census_after", Describe(after));
|
||||
EXPECT_LE(added, GeometricPoolBound(kDraws + 1))
|
||||
<< "a frame needing " << kDraws << " descriptor sets added " << added << " pools; doubling the slot's "
|
||||
<< "largest pool needs at most " << GeometricPoolBound(kDraws + 1) << ". Before: " << Describe(before)
|
||||
EXPECT_LE(added, GeometricPoolBound(held + 1))
|
||||
<< "a frame needing " << held << " descriptor sets at once added " << added << " pools; doubling the "
|
||||
<< "slot's largest pool needs at most " << GeometricPoolBound(held + 1) << ". Before: " << Describe(before)
|
||||
<< "; after: " << Describe(after);
|
||||
}
|
||||
|
||||
@@ -327,19 +343,20 @@ void main() { o_color = texture(uTex, vec2(0.5)); }
|
||||
RecordProperty("quiet_frames", std::to_string(quietFrames));
|
||||
RecordProperty("census_after_quiet", Describe(afterQuiet));
|
||||
RecordProperty("census_after_second_burst", Describe(afterSecondBurst));
|
||||
ASSERT_GE(afterBurst.cachedSets, static_cast<std::uint64_t>(kDraws))
|
||||
const std::uint64_t held = BurstSetsHeldAtOnce();
|
||||
ASSERT_GE(afterBurst.cachedSets, held)
|
||||
<< "the burst did not allocate one descriptor set per draw: " << Describe(afterBurst);
|
||||
EXPECT_GT(afterQuiet.slotTrims, afterBurst.slotTrims)
|
||||
<< quietFrames << " frames of one draw each followed a " << kDraws << "-set frame, but no frame slot was "
|
||||
<< "trimmed (MOBILEGL_MAGMA_DESCRIPTOR_TRIM_FRAMES=" << trimFrames << "). After the burst: "
|
||||
<< Describe(afterBurst) << "; after the quiet frames: " << Describe(afterQuiet);
|
||||
EXPECT_LE(afterQuiet.cachedSets + kDraws / 2, afterBurst.cachedSets)
|
||||
EXPECT_LE(afterQuiet.cachedSets + held / 2, afterBurst.cachedSets)
|
||||
<< "the trim did not give the burst's sets back. After the burst: " << Describe(afterBurst)
|
||||
<< "; after the quiet frames: " << Describe(afterQuiet);
|
||||
EXPECT_LT(afterQuiet.pools, afterBurst.pools)
|
||||
<< "the trim did not give the burst's pools back. After the burst: " << Describe(afterBurst)
|
||||
<< "; after the quiet frames: " << Describe(afterQuiet);
|
||||
EXPECT_GE(afterSecondBurst.cachedSets, afterQuiet.cachedSets + kDraws)
|
||||
EXPECT_GE(afterSecondBurst.cachedSets, afterQuiet.cachedSets + held)
|
||||
<< "the second burst was not served by freshly allocated sets: " << Describe(afterSecondBurst);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "../Harness/HeadlessGL.h"
|
||||
#include "../Harness/PipeStatsWindow.h"
|
||||
#include "../Harness/ScenarioFixture.h"
|
||||
|
||||
#ifdef GLAPI
|
||||
@@ -123,29 +124,21 @@ void main() { o_color = vec4(1.0); }
|
||||
return (end != nullptr && *end == '\0') ? parsed : 0;
|
||||
}
|
||||
|
||||
// The library log, for the arming assertion. Same machinery and reasoning as
|
||||
// UnlocatedIoBlockScenario: MOBILEGL_LOG_FILE_PATH is read at log-init, every process in
|
||||
// the lane appends to the file, and only bytes appended after the snapshot count.
|
||||
std::filesystem::path LibraryLogPath() {
|
||||
const char* path = std::getenv("MOBILEGL_LOG_FILE_PATH");
|
||||
return (path != nullptr && *path != '\0') ? std::filesystem::path(path) : std::filesystem::path();
|
||||
}
|
||||
// The library log, for the arming assertion. MOBILEGL_LOG_FILE_PATH is read at log-init,
|
||||
// every process in the lane appends to it, and only bytes appended after the snapshot
|
||||
// count. P11 M2: ON A SPLIT BUILD IT IS A BASE NAME - the library writes one file per role
|
||||
// (PipeStatsWindow.h) - and the latched line comes from the RENDERER, which under a
|
||||
// transport is the server role: the apply thread under inproc, the spawned server process
|
||||
// under spawn (it inherits this entry's environment, budget and log base included). So the
|
||||
// mark and the read cover both roles, as PrimitivesGeneratedNoXfbScenario's arming does; a
|
||||
// read of the literal base found no file and reported an unsplit renderer. In the pull
|
||||
// build the client role is the whole log.
|
||||
std::string LibraryLogPath() { return PipeStatsWindow::LibraryLogPath(); }
|
||||
|
||||
std::uintmax_t LibraryLogSize() {
|
||||
std::error_code ec;
|
||||
const std::filesystem::path path = LibraryLogPath();
|
||||
if (path.empty()) return 0;
|
||||
const std::uintmax_t size = std::filesystem::file_size(path, ec);
|
||||
return ec ? 0 : size;
|
||||
}
|
||||
PipeStatsWindow::LogMark LibraryLogSize() { return PipeStatsWindow::MarkLaneLog(); }
|
||||
|
||||
std::string LibraryLogSince(std::uintmax_t offset) {
|
||||
const std::filesystem::path path = LibraryLogPath();
|
||||
if (path.empty()) return {};
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file.good()) return {};
|
||||
file.seekg(static_cast<std::streamoff>(offset));
|
||||
return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
std::string LibraryLogSince(const PipeStatsWindow::LogMark& mark) {
|
||||
return PipeStatsWindow::ReadLaneLogSince(mark);
|
||||
}
|
||||
|
||||
std::string Describe(const Rgba8& c) {
|
||||
@@ -338,7 +331,7 @@ void main() { o_color = vec4(1.0); }
|
||||
return ReadPixels(kSide, kSide);
|
||||
}
|
||||
|
||||
std::uintmax_t m_logBefore = 0;
|
||||
PipeStatsWindow::LogMark m_logBefore{};
|
||||
GLuint m_vao = 0;
|
||||
GLuint m_vbo = 0;
|
||||
GLuint m_rectProgram = 0;
|
||||
|
||||
@@ -58,7 +58,13 @@ FIXTURE_ENTRIES = {"TcpServer.Start", "TcpServer.Stop"}
|
||||
# the server's own view/attachment identity out of this process.
|
||||
# A cross-process hold and a cross-process cache peek are server-side knobs neither exists yet;
|
||||
# until they do, naming the two scenarios here keeps the tolerance from widening for anything else.
|
||||
MAGMA_INPROC_ONLY = ("MagmaRunAheadScenario.", "MagmaWireCacheScenario.")
|
||||
# DescriptorPoolGrowthScenario (P11 M2, the `.DescPool.` entry): both cases read the renderer's
|
||||
# pool census (DirectVulkan::GetDescriptorPoolCensus), an in-process read -
|
||||
# on spawn and tcp the pools live in the server process and the census
|
||||
# answers unavailable, so a copy there checks pixels under a name claiming
|
||||
# the pools. The pixels do run on every arm: the Espryt entries and the
|
||||
# Magma informational and full-suite tiers.
|
||||
MAGMA_INPROC_ONLY = ("MagmaRunAheadScenario.", "MagmaWireCacheScenario.", "DescriptorPoolGrowthScenario.")
|
||||
|
||||
# P7 wave 2-B2: THE SANCTIONED ASYMMETRY THAT IS NOT INPROC-ONLY - these exist on split AND
|
||||
# spawn and cannot exist on tcp. Every MGITEST_MAGMA_FORCE_* knob is read BY THE SERVER
|
||||
@@ -101,6 +107,18 @@ MAGMA_INPROC_ONLY = ("MagmaRunAheadScenario.", "MagmaWireCacheScenario.")
|
||||
# SERVER's VulkanRenderer reads to pin the GL_PRIMITIVES_GENERATED reroute on - the knob-free
|
||||
# `.PrimGen.` copies (the bring-up probe's Auto verdict) keep their tcp entries. Eight cases, eight
|
||||
# tails.
|
||||
# P11 M2: the `.SplitRecording64.` entries set MOBILEGL_MAGMA_MAX_DRAWS_PER_COMMAND_BUFFER=64, which
|
||||
# the SERVER's VulkanRenderer reads (SplitOversizedRecording), and assert the line it latches - the
|
||||
# knob-free `.Oversized.` copies (the default budget, dev's control) keep their tcp entries. Eight
|
||||
# cases, eight tails.
|
||||
SPLIT_RECORDING_CASES = ("EveryDrawOfTheFrameLandsAcrossCommandBufferSplits",
|
||||
"ADepthOccluderDrawnBeforeTheSplitHidesADrawAfterIt",
|
||||
"AStencilMarkMadeBeforeTheSplitGatesADrawAfterIt",
|
||||
"BlendingAccumulatesOntoPixelsWrittenBeforeTheSplit",
|
||||
"AMultisampleTargetKeepsItsSamplesAcrossTheSplit",
|
||||
"OcclusionQueriesOpenAcrossTheSplitCountBothSides",
|
||||
"APrimitivesGeneratedQueryOpenAcrossTheSplitCountsBothSides",
|
||||
"ATransformFeedbackCaptureActiveAcrossTheSplitAppendsEveryDraw")
|
||||
PRIMGEN_REROUTE_CASES = ("CountsADrawMadeWithNoCaptureSpan",
|
||||
"CountsUnderRasterizerDiscardWithNoCaptureSpan",
|
||||
"CountsATessellatedPatchWithNoCaptureSpan",
|
||||
@@ -119,7 +137,8 @@ MAGMA_SERVER_ENV_KNOB_NO_TCP = (".ShaderMip1.", ".ShaderMip2.", ".DepthMip.",
|
||||
".Reclaim.MagmaWireReclaimScenario.ManySmallRespecifyAndDrawRoundsStayUnderTheStoreCountCeiling",
|
||||
".Reclaim.MagmaWireReclaimScenario.ADrawAfterTheEarlyReclaimFollowsTheNewStoreNotTheMemoizedHandle",
|
||||
".Reclaim.MagmaWireReclaimScenario.DescriptorSetsRewindInsideOneLongFrameAfterTheirSubmitRetires") + tuple(
|
||||
f".PrimGenReroute.PrimitivesGeneratedNoXfbScenario.{case}" for case in PRIMGEN_REROUTE_CASES)
|
||||
f".PrimGenReroute.PrimitivesGeneratedNoXfbScenario.{case}" for case in PRIMGEN_REROUTE_CASES) + tuple(
|
||||
f".SplitRecording64.OversizedRecordingSplitScenario.{case}" for case in SPLIT_RECORDING_CASES)
|
||||
|
||||
|
||||
# P11 A1: THE MIRROR SHAPE - entries that exist on tcp ALONE, by construction. `.AdoptTier0.` runs
|
||||
|
||||
Reference in New Issue
Block a user