Пример #1
0
def test_oclw_kernelschedule():
    '''Check the OpenCLWriter class kernelschedule_node visitor produces
    the expected C code.

    '''

    # The kernelschedule OpenCL Backend relies on abstrct methods that
    # need to be implemented by the APIs. A generic kernelschedule will
    # produce a NotImplementedError.
    oclwriter = OpenCLWriter()
    kschedule = KernelSchedule("kname")
    with pytest.raises(NotImplementedError) as error:
        _ = oclwriter(kschedule)
    assert "Abstract property. Which symbols are data arguments is " \
        "API-specific." in str(error)

    # Mock abstract properties. (pytest monkeypatch does not work
    # with properties, used sub-class instead)
    class MockSymbolTable(SymbolTable):
        ''' Mock needed abstract methods of the Symbol Table '''
        @property
        def iteration_indices(self):
            return self.argument_list[:2]

        @property
        def data_arguments(self):
            return self.argument_list[2:]
    kschedule.symbol_table.__class__ = MockSymbolTable

    # Create a sample symbol table and kernel schedule
    interface = Symbol.Argument(access=Symbol.Access.UNKNOWN)
    i = Symbol('i', 'integer', interface=interface)
    j = Symbol('j', 'integer', interface=interface)
    data1 = Symbol('data1', 'real', [10, 10], interface=interface)
    data2 = Symbol('data2', 'real', [10, 10], interface=interface)
    kschedule.symbol_table.add(i)
    kschedule.symbol_table.add(j)
    kschedule.symbol_table.add(data1)
    kschedule.symbol_table.add(data2)
    kschedule.symbol_table.specify_argument_list([i, j, data1, data2])
    kschedule.addchild(Return(parent=kschedule))

    result = oclwriter(kschedule)
    print(result)
    assert result == "" \
        "__kernel void kname(\n" \
        "  __global double * restrict data1,\n" \
        "  __global double * restrict data2\n" \
        "  ){\n" \
        "  int data1LEN1 = get_global_size(0);\n" \
        "  int data1LEN2 = get_global_size(1);\n" \
        "  int data2LEN1 = get_global_size(0);\n" \
        "  int data2LEN2 = get_global_size(1);\n" \
        "  int i = get_global_id(0);\n" \
        "  int j = get_global_id(1);\n" \
        "  return;\n" \
        "}\n"
Пример #2
0
def test_oclw_initialization():
    '''Test that the OpenCLWriter-specific parameters are error checked'''

    # OCLWriter can be initialized with default values
    oclwriter = OpenCLWriter()
    assert oclwriter._kernels_local_size == 1

    # Pass a kernels_local_size parameter
    with pytest.raises(TypeError) as error:
        oclwriter = OpenCLWriter(kernels_local_size='invalid')
    assert "kernel_local_size should be an integer but found 'str'." \
        in str(error)

    with pytest.raises(ValueError) as error:
        oclwriter = OpenCLWriter(kernels_local_size=-4)
    assert "kernel_local_size should be a positive integer but found -4." \
        in str(error)

    oclwriter = OpenCLWriter(kernels_local_size=4)
    assert oclwriter._kernels_local_size == 4
Пример #3
0
def test_oclw_gen_declaration():
    '''Check the OpenCLWriter class gen_declaration method produces
    the expected declarations.

    '''
    oclwriter = OpenCLWriter()

    # Basic entry - Scalar are passed by value and don't have additional
    # qualifiers.
    symbol = Symbol("dummy1", "integer")
    result = oclwriter.gen_declaration(symbol)
    assert result == "int dummy1"

    # Array argument has a memory qualifier (only __global for now)
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2])
    result = oclwriter.gen_declaration(symbol)
    assert result == "__global int * restrict dummy2"

    # Array with unknown intent
    symbol = Symbol("dummy2", "integer", shape=[2, None, 2],
                    interface=Symbol.Argument(access=Symbol.Access.UNKNOWN))
    result = oclwriter.gen_declaration(symbol)
    assert result == "__global int * restrict dummy2"
Пример #4
0
def test_opencl_code_generation_with_boundary_mask():
    ''' Tests that OpenCL kernel generated after applying the
    GOMoveIterationBoundariesInsideKernelTrans has the 4 boundary values as
    kernel arguments and has a masking statement at the beginning of the
    executable code.
    '''
    psy, _ = get_invoke("single_invoke.f90", API, idx=0, dist_mem=False)
    sched = psy.invokes.invoke_list[0].schedule
    kernel = sched.children[0].loop_body[0].loop_body[0]  # compute_cu kernel
    trans = GOMoveIterationBoundariesInsideKernelTrans()
    trans.apply(kernel)
    kschedule = kernel.get_kernel_schedule()

    expected_code = ("__kernel void compute_cu_code(\n"
                     "  __global double * restrict cu,\n"
                     "  __global double * restrict p,\n"
                     "  __global double * restrict u,\n"
                     "  int xstart,\n"
                     "  int xstop,\n"
                     "  int ystart,\n"
                     "  int ystop\n"
                     "  ){\n"
                     "  int cuLEN1 = get_global_size(0);\n"
                     "  int cuLEN2 = get_global_size(1);\n"
                     "  int pLEN1 = get_global_size(0);\n"
                     "  int pLEN2 = get_global_size(1);\n"
                     "  int uLEN1 = get_global_size(0);\n"
                     "  int uLEN2 = get_global_size(1);\n"
                     "  int i = get_global_id(0);\n"
                     "  int j = get_global_id(1);\n"
                     "  if ((((i < xstart) || (i > xstop)) || ((j < ystart) ||"
                     " (j > ystop)))) {\n"
                     "    return;\n"
                     "  }\n"
                     "  cu[j * cuLEN1 + i] = ((0.5e0 * (p[j * pLEN1 + (i + 1)]"
                     " + p[j * pLEN1 + i])) * u[j * uLEN1 + i]);\n"
                     "}\n\n")

    openclwriter = OpenCLWriter()
    assert expected_code == openclwriter(kschedule)
Пример #5
0
def test_oclw_gen_array_length_variables():
    '''Check the OpenCLWriter class gen_array_length_variables method produces
    the expected declarations.

    '''
    oclwriter = OpenCLWriter()

    # A scalar should not return any LEN variables
    symbol1 = DataSymbol("dummy2LEN1", INTEGER_TYPE)
    result = oclwriter.gen_array_length_variables(symbol1)
    assert result == ""

    # Array with 1 dimension generates 1 length variable
    array_type = ArrayType(INTEGER_TYPE, [2])
    symbol2 = DataSymbol("dummy1", array_type)
    result = oclwriter.gen_array_length_variables(symbol2)
    assert result == "int dummy1LEN1 = get_global_size(0);\n"

    # Array with multiple dimension generates one variable per dimension
    array_type = ArrayType(INTEGER_TYPE, [2, ArrayType.Extent.ATTRIBUTE, 2])
    symbol3 = DataSymbol("dummy2", array_type)
    result = oclwriter.gen_array_length_variables(symbol3)
    assert result == "int dummy2LEN1 = get_global_size(0);\n" \
        "int dummy2LEN2 = get_global_size(1);\n" \
        "int dummy2LEN3 = get_global_size(2);\n"

    # Create a symbol table
    symtab = SymbolTable()
    symtab.add(symbol1)
    symtab.add(symbol2)
    symtab.add(symbol3)

    # If there are no name clashes, generate array length variables.
    result = oclwriter.gen_array_length_variables(symbol2, symtab)
    assert result == "int dummy1LEN1 = get_global_size(0);\n"

    with pytest.raises(VisitorError) as excinfo:
        _ = oclwriter.gen_array_length_variables(symbol3, symtab)
    assert "Unable to declare the variable 'dummy2LEN1' to store the length " \
        "of 'dummy2' because the Symbol Table already contains a symbol with" \
        " the same name." in str(excinfo.value)
Пример #6
0
def test_oclw_kernelschedule():
    '''Check the OpenCLWriter class kernelschedule_node visitor produces
    the expected OpenCL code.

    '''

    # The kernelschedule OpenCL Backend relies on abstract methods that
    # need to be implemented by the APIs. A generic kernelschedule will
    # produce a NotImplementedError.
    oclwriter = OpenCLWriter()
    kschedule = KernelSchedule("kname")
    with pytest.raises(NotImplementedError) as error:
        _ = oclwriter(kschedule)
    assert "Abstract property. Which symbols are data arguments is " \
        "API-specific." in str(error.value)

    # Mock abstract properties. (pytest monkeypatch does not work
    # with properties, used sub-class instead)
    class MockSymbolTable(SymbolTable):
        ''' Mock needed abstract methods of the Symbol Table '''
        @property
        def iteration_indices(self):
            return self.argument_list[:2]

        @property
        def data_arguments(self):
            return self.argument_list[2:]

    kschedule.symbol_table.__class__ = MockSymbolTable

    # Create a sample symbol table and kernel schedule
    interface = ArgumentInterface(ArgumentInterface.Access.UNKNOWN)
    i = DataSymbol('i', INTEGER_TYPE, interface=interface)
    j = DataSymbol('j', INTEGER_TYPE, interface=interface)
    array_type = ArrayType(REAL_TYPE, [10, 10])
    data1 = DataSymbol('data1', array_type, interface=interface)
    data2 = DataSymbol('data2', array_type, interface=interface)
    kschedule.symbol_table.add(i)
    kschedule.symbol_table.add(j)
    kschedule.symbol_table.add(data1)
    kschedule.symbol_table.add(data2)
    kschedule.symbol_table.specify_argument_list([i, j, data1, data2])
    kschedule.addchild(Return(parent=kschedule))

    result = oclwriter(kschedule)
    assert result == "" \
        "__kernel void kname(\n" \
        "  __global double * restrict data1,\n" \
        "  __global double * restrict data2\n" \
        "  ){\n" \
        "  int data1LEN1 = get_global_size(0);\n" \
        "  int data1LEN2 = get_global_size(1);\n" \
        "  int data2LEN1 = get_global_size(0);\n" \
        "  int data2LEN2 = get_global_size(1);\n" \
        "  int i = get_global_id(0);\n" \
        "  int j = get_global_id(1);\n" \
        "  return;\n" \
        "}\n\n"

    # Set a local_size value different to 1 into the KernelSchedule
    oclwriter = OpenCLWriter(kernels_local_size=4)
    result = oclwriter(kschedule)

    assert result == "" \
        "__attribute__((reqd_work_group_size(4, 1, 1)))\n" \
        "__kernel void kname(\n" \
        "  __global double * restrict data1,\n" \
        "  __global double * restrict data2\n" \
        "  ){\n" \
        "  int data1LEN1 = get_global_size(0);\n" \
        "  int data1LEN2 = get_global_size(1);\n" \
        "  int data2LEN1 = get_global_size(0);\n" \
        "  int data2LEN2 = get_global_size(1);\n" \
        "  int i = get_global_id(0);\n" \
        "  int j = get_global_id(1);\n" \
        "  return;\n" \
        "}\n\n"

    # Add a symbol with a deferred interface and check that this raises the
    # expected error
    array_type = ArrayType(REAL_TYPE, [10, 10])
    kschedule.symbol_table.add(
        DataSymbol('broken', array_type, interface=UnresolvedInterface()))
    with pytest.raises(VisitorError) as err:
        _ = oclwriter(kschedule)
    assert ("symbol table contains unresolved data entries (i.e. that have no "
            "defined Interface) which are not used purely to define the "
            "precision of other symbols: 'broken'" in str(err.value))