From 7f4098d8356ccbac463e9ad2a444e15a10dfc07d Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Wed, 12 Feb 2025 08:44:57 +0000 Subject: [PATCH] Add vk_subgroup_zoo tests for maximal reconvergence behaviour Diverged threads which re-converge at expected points --- util/test/demos/vk/vk_subgroup_zoo.cpp | 126 +++++++++++++++++++++- util/test/tests/Vulkan/VK_Subgroup_Zoo.py | 71 +++++++----- 2 files changed, 165 insertions(+), 32 deletions(-) diff --git a/util/test/demos/vk/vk_subgroup_zoo.cpp b/util/test/demos/vk/vk_subgroup_zoo.cpp index a3cd2b658..bb32dffbd 100644 --- a/util/test/demos/vk/vk_subgroup_zoo.cpp +++ b/util/test/demos/vk/vk_subgroup_zoo.cpp @@ -129,16 +129,136 @@ layout(binding = 0, std430) buffer outbuftype { layout(local_size_x = GROUP_SIZE_X, local_size_y = GROUP_SIZE_Y, local_size_z = 1) in; +vec4 funcD(uint id) +{ + return vec4(subgroupAdd(id/2)); +} + +vec4 nestedFunc(uint id) +{ + vec4 ret = funcD(id/3); + ret.w = subgroupAdd(id); + return ret; +} + +vec4 funcA(uint id) +{ + return nestedFunc(id*2); +} + +vec4 funcB(uint id) +{ + return nestedFunc(id*4); +} + +vec4 funcTest(uint id) +{ + if ((id % 2) == 0) + { + return vec4(0); + } + else + { + float value = subgroupAdd(id); + if (id < 10) + { + return vec4(value); + } + value += subgroupAdd(id/2); + return vec4(value); + } +} + +void SetOuput(vec4 data) +{ + outbuf.data[push.test].vals[gl_LocalInvocationID.y * GROUP_SIZE_X + gl_LocalInvocationID.x] = data; +} void main() { vec4 data = vec4(0); + uint id = gl_SubgroupInvocationID; + SetOuput(data); if(IsTest(0)) - data = vec4(gl_SubgroupInvocationID, 0, 0, 0); + { + data.x = id; + } else if(IsTest(1)) - data = vec4(subgroupAdd(gl_SubgroupInvocationID), 0, 0, 0); + { + data.x = subgroupAdd(id); + } + else if(IsTest(2)) + { + // Diverged threads which reconverge + if (id < 10) + { + // active threads 0-9 + data.x = subgroupAdd(id); - outbuf.data[push.test].vals[gl_LocalInvocationID.y * GROUP_SIZE_X + gl_LocalInvocationID.x] = data; + if ((id % 2) == 0) + data.y = subgroupAdd(id); + else + data.y = subgroupAdd(id); + + data.x += subgroupAdd(id); + } + else + { + // active threads 10... + data.x = subgroupAdd(id); + } + data.y = subgroupAdd(id); + } + else if(IsTest(3)) + { + // Converged threads calling a function + data = funcTest(id); + data.y = subgroupAdd(id); + } + else if(IsTest(4)) + { + // Converged threads calling a function which has a nested function call in it + data = nestedFunc(id); + data.y = subgroupAdd(id); + } + else if(IsTest(5)) + { + // Diverged threads calling the same function + if (id < 10) + { + data = funcD(id); + } + else + { + data = funcD(id); + } + data.y = subgroupAdd(id); + } + else if(IsTest(6)) + { + // Diverged threads calling the same function which has a nested function call in it + if (id < 10) + { + data = funcA(id); + } + else + { + data = funcB(id); + } + data.y = subgroupAdd(id); + } + else if(IsTest(7)) + { + // Diverged threads which early exit + if (id < 10) + { + data.x = subgroupAdd(id+10); + SetOuput(data); + return; + } + data.x = subgroupAdd(id); + } + SetOuput(data); } )EOSHADER"; diff --git a/util/test/tests/Vulkan/VK_Subgroup_Zoo.py b/util/test/tests/Vulkan/VK_Subgroup_Zoo.py index 9771a9348..815aee785 100644 --- a/util/test/tests/Vulkan/VK_Subgroup_Zoo.py +++ b/util/test/tests/Vulkan/VK_Subgroup_Zoo.py @@ -149,7 +149,7 @@ class VK_Subgroup_Zoo(rdtest.TestCase): rdtest.log.success(f"Test {idx} successful") rdtest.log.end_section("Graphics tests") - + overallFailed = False for comp_dim in compute_dims: rdtest.log.begin_section( f"Compute tests with {comp_dim.customName} workgroup") @@ -175,6 +175,7 @@ class VK_Subgroup_Zoo(rdtest.TestCase): bufdata = self.controller.GetBufferData( rw[0].descriptor.resource, test*16*1024, 16*1024) + failed = False for t in thread_checks: xrange = 1 yrange = dim[1] @@ -195,39 +196,51 @@ class VK_Subgroup_Zoo(rdtest.TestCase): if x >= dim[0] or y >= dim[1]: continue - real = struct.unpack_from( - "4f", bufdata, 16*y*dim[0] + 16*x) + try: + real = struct.unpack_from( + "4f", bufdata, 16*y*dim[0] + 16*x) - trace = self.controller.DebugThread( - (0, 0, 0), (x, y, z)) + trace = self.controller.DebugThread( + (0, 0, 0), (x, y, z)) - _, variables = self.process_trace(trace) + _, variables = self.process_trace(trace) - if trace.debugger is None: + if trace.debugger is None: + raise rdtest.TestFailureException(f"Test {test} at {action.eventId} got no debug result at {x},{y},{z}") + + # Find the source variable 'data' at the highest instruction index + maxInstInfo = None + for instInfo in trace.instInfo: + for v in instInfo.sourceVars: + if v.name == 'data': + maxInstInfo = instInfo + break + + sourceVars = [v for v in maxInstInfo.sourceVars if v.name == 'data'] + if len(sourceVars) != 1: + raise rdtest.TestFailureException(f"Couldn't find compute source variable 'data' {x}, {y}, {z}") + + debugged = self.evaluate_source_var( + sourceVars[0], variables) + + debuggedValue = list(debugged.value.f32v[0:4]) + + if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06): + raise rdtest.TestFailureException(f"EID:{action.eventId} TID:{x},{y},{z} debugged thread value {debuggedValue} does not match output {real}") + + except rdtest.TestFailureException as ex: + rdtest.log.error(f"Test {test} failed {ex}") + failed = True + continue + finally: self.controller.FreeTrace(trace) - rdtest.log.error( - f"Test {test} at {action.eventId} got no debug result at {x},{y},{z}") - continue - - sourceVars = [ - v for v in trace.instInfo[-1].sourceVars if v.name == 'data'] - - if len(sourceVars) != 1: - rdtest.log.error( - "Couldn't find compute data variable") - continue - - debugged = self.evaluate_source_var( - sourceVars[0], variables) - - debuggedValue = list(debugged.value.f32v[0:4]) - - if not rdtest.value_compare(real, debuggedValue, eps=5.0E-06): - rdtest.log.error( - f"Test {test} at {action.eventId} debugged thread value {debuggedValue} at {x},{y},{z} does not match output {real}") - - rdtest.log.success(f"Test {test} successful") + overallFailed |= failed + if not failed: + rdtest.log.success(f"Test {test} successful") rdtest.log.end_section( f"Compute tests with {comp_dim.customName} workgroup") + + if overallFailed: + raise rdtest.TestFailureException("Some tests were not as expected")