File: howto.rst

package info (click to toggle)
pyopencl 2016.1%2Bgit20161130-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 2,220 kB
  • ctags: 3,039
  • sloc: python: 20,232; cpp: 8,002; lisp: 4,361; makefile: 192; ansic: 103; sh: 1
file content (105 lines) | stat: -rw-r--r-- 3,329 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
How-tos
=======

How to use struct types with PyOpenCL
-------------------------------------

We import and initialize PyOpenCL as usual:

.. doctest::
    :options: +ELLIPSIS

    >>> import numpy as np
    >>> import pyopencl as cl
    >>> import pyopencl.tools
    >>> import pyopencl.array

    >>> ctx = cl.create_some_context(interactive=False)
    >>> queue = cl.CommandQueue(ctx)

Then, suppose we would like to declare a struct consisting of an integer and a
floating point number. We first create a :class:`numpy.dtype` along these
lines:

.. doctest::

    >>> my_struct = np.dtype([("field1", np.int32), ("field2", np.float32)])
    >>> print(my_struct)
    [('field1', '<i4'), ('field2', '<f4')]

.. note::

    Not all :mod:`numpy` dtypes are supported yet. For example strings (and
    generally things that have a shape of their own) are not supported.

Since OpenCL C may have a different opinion for :mod:`numpy` on how the struct
should be laid out, for example because of `alignment
<https://en.wikipedia.org/wiki/Data_structure_alignment>`_. So as a first step, we
match our dtype against CL's version:

.. doctest::

    >>> my_struct, my_struct_c_decl = cl.tools.match_dtype_to_c_struct(
    ...    ctx.devices[0], "my_struct", my_struct)
    >>> print(my_struct_c_decl)
    typedef struct {
      int field1;
      float field2;
    } my_struct;
    <BLANKLINE>
    <BLANKLINE>

We then tell PyOpenCL about our new type.

.. doctest::

    >>> my_struct = cl.tools.get_or_register_dtype("my_struct", my_struct)

Next, we can create some data of that type on the host and transfer it to
the device:

.. doctest::

    >>> ary_host = np.empty(20, my_struct)
    >>> ary_host["field1"].fill(217)
    >>> ary_host["field2"].fill(1000)
    >>> ary_host[13]["field2"] = 12
    >>> print(ary_host)
    [(217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)
     (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)
     (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 12.0) (217, 1000.0)
     (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0) (217, 1000.0)]

    >>> ary = cl.array.to_device(queue, ary_host)

We can then operate on the array with our own kernels:

.. doctest::

    >>> prg = cl.Program(ctx, my_struct_c_decl + """
    ...     __kernel void set_to_1(__global my_struct *a)
    ...     {
    ...         a[get_global_id(0)].field1 = 1;
    ...     }
    ...     """).build()

    >>> evt = prg.set_to_1(queue, ary.shape, None, ary.data)
    >>> print(ary)
    [(1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
     (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
     (1, 1000.0) (1, 12.0) (1, 1000.0) (1, 1000.0) (1, 1000.0) (1, 1000.0)
     (1, 1000.0) (1, 1000.0)]

as well as with PyOpenCL's built-in operations:

.. doctest::

    >>> from pyopencl.elementwise import ElementwiseKernel
    >>> elwise = ElementwiseKernel(ctx, "my_struct *a", "a[i].field1 = 2;",
    ...    preamble=my_struct_c_decl)
    >>> evt = elwise(ary)
    >>> print(ary)
    [(2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
     (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
     (2, 1000.0) (2, 12.0) (2, 1000.0) (2, 1000.0) (2, 1000.0) (2, 1000.0)
     (2, 1000.0) (2, 1000.0)]