1# Copyright (C) 2016 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from __future__ import absolute_import 16 17import itertools 18 19from harness.test_base_remote import TestBaseRemote 20from harness.decorators import ( 21 ordered_test, 22 wimpy, 23) 24from harness.assert_mixins import CoordinateAssertionsMixin 25 26from reduce_common import ( 27 REDUCE_ITERATIONS, 28 REDUCE_STARTVAL, 29 REDUCE_SCRIPT, 30 X_TESTS, 31 Y_TESTS, 32 Z_TESTS, 33 ReductionMixin, 34) 35 36 37def coords_range_3d(x_range, y_range, z_range): 38 count = max((x_range, y_range, z_range)) 39 x = itertools.cycle(range(x_range)) 40 y = itertools.cycle(range(y_range)) 41 z = itertools.cycle(range(z_range)) 42 return itertools.islice( 43 itertools.izip(x, y, z), 44 count 45 ) 46 47 48class TestReduce1DSingleThreaded( 49 TestBaseRemote, CoordinateAssertionsMixin, ReductionMixin): 50 """ 51 Reduction kernels for RenderScript are launched using 52 a different `.expand` function than regular `ForEach` kernels and reflect a 53 different API to the invoking program 54 55 Although the debugger implementation for accessing these features tracks 56 this slightly differently for reduction kernels, the user interface should 57 still offer the basic functionality: 58 - breakpoints on a coordinate 59 - tracking, viewing and dumping allocations 60 - listing modules and constituent kernels and types 61 """ 62 63 bundle_target = { 64 'java': 'Reduction', 65 } 66 67 def _delete_breakpoints(self): 68 try: 69 self.do_command('breakpoint delete -f') 70 except self.TestFail: 71 pass 72 73 def setup(self, android): 74 """This test requires to be run on one thread.""" 75 android.push_prop('debug.rs.max-threads', 1) 76 77 def teardown(self, android): 78 """Reset the number of RS threads to the previous value.""" 79 android.pop_prop('debug.rs.max-threads') 80 81 @ordered_test(0) 82 @wimpy 83 def test_setup(self): 84 self.try_command('language renderscript status', []) 85 self.try_command('b find_min_user_type_accum', []) 86 self.try_command('c', []) 87 88 @ordered_test(1) 89 @wimpy 90 def test_renderscript_module_dump(self): 91 """ 92 Generalised Reduction kernels for RenderScript are not tracked in the 93 same way as `ForEach` kernels, and do not have `__attribute__((kernel))` 94 so we need to make sure that when a module contains reduction kernels, 95 `language renderscript module dump` in lldb prints the correct kernels. 96 """ 97 self.try_command( 98 'language renderscript module dump', 99 [ 100 'Reductions: 1', 101 'find_min_user_type', 102 'accumulator: find_min_user_type_accum', 103 'combiner: find_min_user_type_comb', 104 'outconverter: find_min_user_type_outc' 105 ] 106 ) 107 108 @ordered_test(2) 109 @wimpy 110 def test_module_dump_with_foreach_kernel_separate(self): 111 """ 112 The reduction breakpoint is separate from that of a standard kernel 113 function breakpoint, so we need to make sure that when we dump a module, 114 reductions are properly collected and displayed alongside the standard 115 __attribute__((kernel)) functions. 116 Assert that `... module dump` can correctly distinguish between `reduce` 117 kernels and `ForEach` kernels. 118 """ 119 self.try_command( 120 'language renderscript module dump', 121 [ 122 'Kernels: 2', 123 'Reductions: 1', 124 'accumulator: find_min_user_type_accum', 125 'initializer: find_min_user_type_init', 126 'combiner: find_min_user_type_comb', 127 'outconverter: find_min_user_type_outc' 128 ] 129 ) 130 131 @wimpy 132 @ordered_test(3) 133 def test_reduction_breakpoint_set_all_roles_resolved(self): 134 """ 135 Assert that a reduction breakpoint successfully resolves all the 136 functions that make up the reduction kernel 137 """ 138 self.try_command( 139 'language renderscript reduction breakpoint set find_min_user_type', 140 ['Breakpoint(s) created'] 141 ) 142 143 self.try_command( 144 'process continue', 145 expected_regex=[ 146 r'Process \d+ stopped', 147 r'librs.reduce.so`find_min_user_type', 148 r'stop reason = breakpoint' 149 ] 150 ) 151 name = REDUCE_SCRIPT 152 self.try_command( 153 'breakpoint list', 154 expected_regex=[ 155 "RenderScript reduce breakpoint for 'find_min_user_type', locations = 4, resolved = 4", 156 'where = librs.reduce.so`find_min_user_type_init (\+ \d+ )?at %s(.+, resolved,)' % name, 157 'where = librs.reduce.so`find_min_user_type_accum (\+ \d+ )?at %s(.+, resolved,)' % name, 158 'where = librs.reduce.so`find_min_user_type_comb (\+ \d+ )?at %s(.+, resolved,)' % name, 159 'where = librs.reduce.so`find_min_user_type_outc (\+ \d+ )?at %s(.+, resolved,)' % name, 160 ] 161 ) 162 163 @ordered_test(4) 164 def test_reduce_iterations(self): 165 """ 166 Given a reduction, we want to make sure that we break on 167 every accumulator invocation before seeing the outconverter called. 168 This requires the tests to be run single threaded 169 """ 170 self._delete_breakpoints() 171 self.try_command( 172 'language renderscript reduction breakpoint set find_min_user_type -t initializer', 173 ) 174 self.try_command( 175 'process continue', 176 expected_regex=[ 177 r'Process \d+ stopped', 178 r'librs.reduce.so`find_min_user_type_init', 179 r'stop reason = breakpoint', 180 ] 181 ) 182 self._delete_breakpoints() 183 184 self.try_command(( 185 'language renderscript reduction breakpoint ' 186 'set find_min_user_type --function-role accumulator,outconverter'), 187 ['Breakpoint(s) created'] 188 ) 189 for i in range(REDUCE_ITERATIONS): 190 self.try_command( 191 'process continue', 192 expected_regex=[ 193 r'Process \d+ resuming', 194 r'Process \d+ stopped', 195 r'librs.reduce.so`find_min_user_type_accum', 196 r'stop reason = breakpoint' 197 ] 198 ) 199 self.try_command('p val') 200 self.try_command( 201 'p val.b', 202 expected_regex=[ 203 r'^\((const )?int32_t\)\s*\$\d+ = %s\s*$' % ( 204 i + REDUCE_STARTVAL) 205 ] 206 ) 207 # We should then finally break on the outconverter 208 self.try_command( 209 'process continue', 210 expected_regex=[ 211 r'Process \d+ resuming', 212 r'Process \d+ stopped', 213 r'librs.reduce.so`find_min_user_type_outc', 214 r'stop reason = breakpoint' 215 ] 216 ) 217 218 @ordered_test(5) 219 def test_function_role_breakpoints_combinations(self): 220 func_role_combinations = itertools.combinations( 221 ('accumulator', 'initializer'), 222 r=2 223 ) 224 self._test_func_role_combinations(func_role_combinations) 225 226 @wimpy 227 @ordered_test(6) 228 def test_resolve_function_role_all_reduce_functions(self): 229 """ 230 Assert that a reduction breakpoint successfully resolves all the 231 functions that make up the reduction kernel when the parameter `all` is 232 passed to `--function-role` for the breakpoint command 233 """ 234 self._delete_breakpoints() 235 self.try_command( 236 'language renderscript reduction breakpoint set find_min_user_type -t all', 237 [r'Breakpoint(s) created'] 238 ) 239 self.try_command('c', []) 240 breakpoints_match = [ 241 r"where = librs.reduce.so`%s (\+ \d+ )?at %s:\d+, address = 0x[0-9a-fA-F]+, resolved" % ( 242 'find_min_user_type_%s' % func_match, 243 REDUCE_SCRIPT 244 ) 245 for func_match in ('accum', 'init', 'comb', 'outc') 246 ] 247 self.try_command( 248 'breakpoint list', 249 expected_regex=[ 250 r"Current breakpoints:", 251 r"RenderScript reduce breakpoint for 'find_min_user_type', locations = 4, resolved = 4", 252 r"Names:", 253 r"RenderScriptReduction", 254 ] + breakpoints_match 255 ) 256 257 @ordered_test(8) 258 def test_reduce_breakpoint_conditional_1d_coordinate(self): 259 """ 260 Assert that breakpoints conditional on an allocation coordinate 261 are only triggered on that coordinate 262 """ 263 for x, _, __ in sorted(coords_range_3d(X_TESTS, Y_TESTS, Z_TESTS)): 264 self._delete_breakpoints() 265 self.assert_coord_bp_set( 266 'find_min_user_type -t accumulator', 267 x, 268 kernel_type='reduction' 269 ) 270 self.assert_coord_stop('reduce', 'find_min_user_type', x) 271 # Step *into* the function so locals are available 272 # FIXME remove the need for `next` here; skip the function prologue 273 self.try_command('n') 274 self.try_command('p accum->a') 275 self.try_command('p accum->b') 276 277 @ordered_test('last') 278 def test_exit(self): 279 self.try_command('process kill', []) 280