blob: 9653c020e0453002a4f26924936fb2114deda137 [file] [log] [blame]
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
import itertools
from harness.test_base_remote import TestBaseRemote
from harness.decorators import (
ordered_test,
wimpy,
)
from harness.assert_mixins import CoordinateAssertionsMixin
from reduce_common import (
REDUCE_ITERATIONS,
REDUCE_STARTVAL,
REDUCE_SCRIPT,
X_TESTS,
Y_TESTS,
Z_TESTS,
ReductionMixin,
)
def coords_range_3d(x_range, y_range, z_range):
count = max((x_range, y_range, z_range))
x = itertools.cycle(range(x_range))
y = itertools.cycle(range(y_range))
z = itertools.cycle(range(z_range))
return itertools.islice(
itertools.izip(x, y, z),
count
)
class TestReduce1DSingleThreaded(
TestBaseRemote, CoordinateAssertionsMixin, ReductionMixin):
"""
Reduction kernels for RenderScript are launched using
a different `.expand` function than regular `ForEach` kernels and reflect a
different API to the invoking program
Although the debugger implementation for accessing these features tracks
this slightly differently for reduction kernels, the user interface should
still offer the basic functionality:
- breakpoints on a coordinate
- tracking, viewing and dumping allocations
- listing modules and constituent kernels and types
"""
bundle_target = {
'java': 'Reduction',
}
def _delete_breakpoints(self):
try:
self.do_command('breakpoint delete -f')
except self.TestFail:
pass
def setup(self, android):
"""This test requires to be run on one thread."""
android.push_prop('debug.rs.max-threads', 1)
def teardown(self, android):
"""Reset the number of RS threads to the previous value."""
android.pop_prop('debug.rs.max-threads')
@ordered_test(0)
@wimpy
def test_setup(self):
self.try_command('language renderscript status', [])
self.try_command('b find_min_user_type_accum', [])
self.try_command('c', [])
@ordered_test(1)
@wimpy
def test_renderscript_module_dump(self):
"""
Generalised Reduction kernels for RenderScript are not tracked in the
same way as `ForEach` kernels, and do not have `__attribute__((kernel))`
so we need to make sure that when a module contains reduction kernels,
`language renderscript module dump` in lldb prints the correct kernels.
"""
self.try_command(
'language renderscript module dump',
[
'Reductions: 1',
'find_min_user_type',
'accumulator: find_min_user_type_accum',
'combiner: find_min_user_type_comb',
'outconverter: find_min_user_type_outc'
]
)
@ordered_test(2)
@wimpy
def test_module_dump_with_foreach_kernel_separate(self):
"""
The reduction breakpoint is separate from that of a standard kernel
function breakpoint, so we need to make sure that when we dump a module,
reductions are properly collected and displayed alongside the standard
__attribute__((kernel)) functions.
Assert that `... module dump` can correctly distinguish between `reduce`
kernels and `ForEach` kernels.
"""
self.try_command(
'language renderscript module dump',
[
'Kernels: 2',
'Reductions: 1',
'accumulator: find_min_user_type_accum',
'initializer: find_min_user_type_init',
'combiner: find_min_user_type_comb',
'outconverter: find_min_user_type_outc'
]
)
@wimpy
@ordered_test(3)
def test_reduction_breakpoint_set_all_roles_resolved(self):
"""
Assert that a reduction breakpoint successfully resolves all the
functions that make up the reduction kernel
"""
self.try_command(
'language renderscript reduction breakpoint set find_min_user_type',
['Breakpoint(s) created']
)
self.try_command(
'process continue',
expected_regex=[
r'Process \d+ stopped',
r'librs.reduce.so`find_min_user_type',
r'stop reason = breakpoint'
]
)
name = REDUCE_SCRIPT
self.try_command(
'breakpoint list',
expected_regex=[
"RenderScript reduce breakpoint for 'find_min_user_type', locations = 4, resolved = 4",
'where = librs.reduce.so`find_min_user_type_init (\+ \d+ )?at %s(.+, resolved,)' % name,
'where = librs.reduce.so`find_min_user_type_accum (\+ \d+ )?at %s(.+, resolved,)' % name,
'where = librs.reduce.so`find_min_user_type_comb (\+ \d+ )?at %s(.+, resolved,)' % name,
'where = librs.reduce.so`find_min_user_type_outc (\+ \d+ )?at %s(.+, resolved,)' % name,
]
)
@ordered_test(4)
def test_reduce_iterations(self):
"""
Given a reduction, we want to make sure that we break on
every accumulator invocation before seeing the outconverter called.
This requires the tests to be run single threaded
"""
self._delete_breakpoints()
self.try_command(
'language renderscript reduction breakpoint set find_min_user_type -t initializer',
)
self.try_command(
'process continue',
expected_regex=[
r'Process \d+ stopped',
r'librs.reduce.so`find_min_user_type_init',
r'stop reason = breakpoint',
]
)
self._delete_breakpoints()
self.try_command((
'language renderscript reduction breakpoint '
'set find_min_user_type --function-role accumulator,outconverter'),
['Breakpoint(s) created']
)
for i in range(REDUCE_ITERATIONS):
self.try_command(
'process continue',
expected_regex=[
r'Process \d+ resuming',
r'Process \d+ stopped',
r'librs.reduce.so`find_min_user_type_accum',
r'stop reason = breakpoint'
]
)
self.try_command('p val')
self.try_command(
'p val.b',
expected_regex=[
r'^\((const )?int32_t\)\s*\$\d+ = %s\s*$' % (
i + REDUCE_STARTVAL)
]
)
# We should then finally break on the outconverter
self.try_command(
'process continue',
expected_regex=[
r'Process \d+ resuming',
r'Process \d+ stopped',
r'librs.reduce.so`find_min_user_type_outc',
r'stop reason = breakpoint'
]
)
@ordered_test(5)
def test_function_role_breakpoints_combinations(self):
func_role_combinations = itertools.combinations(
('accumulator', 'initializer'),
r=2
)
self._test_func_role_combinations(func_role_combinations)
@wimpy
@ordered_test(6)
def test_resolve_function_role_all_reduce_functions(self):
"""
Assert that a reduction breakpoint successfully resolves all the
functions that make up the reduction kernel when the parameter `all` is
passed to `--function-role` for the breakpoint command
"""
self._delete_breakpoints()
self.try_command(
'language renderscript reduction breakpoint set find_min_user_type -t all',
[r'Breakpoint(s) created']
)
self.try_command('c', [])
breakpoints_match = [
r"where = librs.reduce.so`%s (\+ \d+ )?at %s:\d+, address = 0x[0-9a-fA-F]+, resolved" % (
'find_min_user_type_%s' % func_match,
REDUCE_SCRIPT
)
for func_match in ('accum', 'init', 'comb', 'outc')
]
self.try_command(
'breakpoint list',
expected_regex=[
r"Current breakpoints:",
r"RenderScript reduce breakpoint for 'find_min_user_type', locations = 4, resolved = 4",
r"Names:",
r"RenderScriptReduction",
] + breakpoints_match
)
@ordered_test(8)
def test_reduce_breakpoint_conditional_1d_coordinate(self):
"""
Assert that breakpoints conditional on an allocation coordinate
are only triggered on that coordinate
"""
for x, _, __ in sorted(coords_range_3d(X_TESTS, Y_TESTS, Z_TESTS)):
self._delete_breakpoints()
self.assert_coord_bp_set(
'find_min_user_type -t accumulator',
x,
kernel_type='reduction'
)
self.assert_coord_stop('reduce', 'find_min_user_type', x)
# Step *into* the function so locals are available
# FIXME remove the need for `next` here; skip the function prologue
self.try_command('n')
self.try_command('p accum->a')
self.try_command('p accum->b')
@ordered_test('last')
def test_exit(self):
self.try_command('process kill', [])