Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] [cc] Doc the workflow for exporting Taichi kernels to C99 source #1756

Merged
merged 16 commits into from
Sep 3, 2020
Merged
22 changes: 11 additions & 11 deletions docs/atomic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ Below is a list of all explicit atomic operations:

Supported atomic operations on each backend:

+----------+-----------+-----------+---------+
| type | CPU/CUDA | OpenGL | Metal |
+==========+===========+===========+=========+
| ``i32`` | OK | OK | OK |
+----------+-----------+-----------+---------+
| ``f32`` | OK | OK | OK |
+----------+-----------+-----------+---------+
| ``i64`` | OK | EXT | N/A |
+----------+-----------+-----------+---------+
| ``f64`` | OK | EXT | N/A |
+----------+-----------+-----------+---------+
+------+-----------+-----------+---------+----------+
| type | CPU/CUDA | OpenGL | Metal | C source |
+======+===========+===========+=========+==========+
| i32 | OK | OK | OK | OK |
+------+-----------+-----------+---------+----------+
| f32 | OK | OK | OK | OK |
+------+-----------+-----------+---------+----------+
| i64 | OK | EXT | N/A | OK |
+------+-----------+-----------+---------+----------+
| f64 | OK | EXT | N/A | OK |
+------+-----------+-----------+---------+----------+

(OK: supported; EXT: require extension; N/A: not available)
205 changes: 205 additions & 0 deletions docs/export_kernels.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
Export Taichi kernels to C source
=================================

The C backend of Taichi allows you to **export Taichi kernels to C source**.

The exported Taichi program consists purely of C99-compatible code and does not require Python. This allows you to use the exported code in a C/C++ project, or even to further compile it to Javascript/Web Assembly via Emscripten.

Each C function corresponds to one Taichi kernel.
For example, ``Tk_init_c6_0()`` may correspond to ``init()`` in ``mpm88.py``.

The exported C code is self-contained for portability. Required Taichi runtime functions are included in the code.

For example, this allows programmers to distribute Taichi programs in
a binary format, by compiling and linking exported C code to their project.

.. warning::

Currently, this feature is only officially supported on the C backend on Linux. In the future, we will support OS X and Windows.


The workflow of exporting
-------------------------

Use ``ti.core.start_recording`` in the Taichi program you want to export.

Suppose you want to export `examples/mpm88.py <https://github.com/taichi-dev/taichi/blob/master/examples/mpm88.py>`_, here is the workflow:

Export YAML
+++++++++++

First, modify ``mpm88.py`` as shown below:

.. code-block:: python

import taichi as ti

ti.core.start_recording('mpm88.yml')
ti.init(arch=ti.cc)

... # your program

Then please execute ``mpm88.py``. Close the GUI window once particles are shown up correctly.

This will save all the kernels in ``mpm88.py`` to ``mpm88.yml``:

.. code-block:: yaml

- action: "compile_kernel"
kernel_name: "init_c6_0"
kernel_source: "void Tk_init_c6_0(struct Ti_Context *ti_ctx) {\n for (Ti_i32 tmp0 = 0; tmp0 < 8192...\n"
- action: "launch_kernel"
kernel_name: "init_c6_0"
...

.. note::

Equivalently, you may also specify these two arguments from environment
variables on Unix-like system:

.. code-block:: bash

TI_ARCH=cc TI_ACTION_RECORD=mpm88.yml python mpm88.py

Compose YAML into a single C file
+++++++++++++++++++++++++++++++++

Now, all necessary information is saved in ``mpm88.yml``, in the form of multiple separate records.
You may want to **compose** the separate kernels into **one single file** for more portability.

We provide a useful CLI tool to do this:

.. code-block:: bash

python3 -m taichi cc_compose mpm88.yml mpm88.c mpm88.h

This composes all the kernels and runtimes in ``mpm88.yml`` into a single C
source file ``mpm88.c``:

.. code-block:: c

...

Ti_i8 Ti_gtmp[1048576];
union Ti_BitCast Ti_args[8];
Ti_i32 Ti_earg[8 * 8];

struct Ti_Context Ti_ctx = { // statically-allocated context for convenience!
&Ti_root, Ti_gtmp, Ti_args, Ti_earg,
};

void Tk_init_c6_0(struct Ti_Context *ti_ctx) {
for (Ti_i32 tmp0 = 0; tmp0 < 8192; tmp0 += 1) {
Ti_i32 tmp1 = tmp0;
Ti_f32 tmp2 = Ti_rand_f32();
Ti_f32 tmp3 = Ti_rand_f32();
Ti_f32 tmp4 = 0.4;
Ti_f32 tmp5 = tmp2 * tmp4;

...

... and a C header file ``mpm88.h`` for declarations of data structures, functions
(Taichi kernels) for this file.

.. note::

The generated C source is promised to be C99 compatible.

It should also be functional when compiled using a C++ compiler.


Calling the exported kernels
----------------------------

Then, link the C file (``mpm88.c``) against your C/C++ project.
Include the header file (``mpm88.h``) when Taichi kernels are called.

For example, calling kernel ``init_c6_0`` can be implemented as follows:

.. code-block:: cpp

#include "mpm88.h"

int main(void) {
...
Tk_init_c6_0(&Ti_ctx);
...
}


Alternatively, if you need multiple Taichi contexts within one program:

.. code-block:: cpp

extern "C" { // if you use mpm88.c instead of renaming it to mpm88.cpp
#include "mpm88.h"
}

class MyRenderer {
...
struct Ti_Context per_renderer_taichi_context;
...
};

MyRenderer::MyRenderer() {
// allocate buffers on your own:
per_renderer_taichi_context.root = malloc(...);
...
Tk_init_c6_0(&per_renderer_taichi_context);
}


Specifying scalar arguments
+++++++++++++++++++++++++++

To specify scalar arguments for kernels:

.. code-block:: cpp

Ti_ctx.args[0].val_f64 = 3.14; // first argument, float64
Ti_ctx.args[1].val_i32 = 233; // second argument, int32
Tk_my_kernel_c8_0(&Ti_ctx);
double ret = Ti_ctx.args[0].val_f64; // return value, float64

printf("my_kernel(3.14, 233) = %lf\n", ret);

Passing external arrays
+++++++++++++++++++++++

To pass external arrays as arguments for kernels:

.. code-block:: cpp

float img[640 * 480 * 3];

Ti_ctx.args[0].ptr_f32 = img; // first argument, float32 pointer to array

// specify the shape of that array:
Ti_ctx.earg[0 * 8 + 0] = 640; // img.shape[0]
Ti_ctx.earg[0 * 8 + 1] = 480; // img.shape[1]
Ti_ctx.earg[0 * 8 + 2] = 3; // img.shape[2]
Tk_matrix_to_ext_arr_c12_0(&Ti_ctx);

// note that the array used in Taichi is row-major:
printf("img[3, 2, 1] = %f\n", img[(3 * 480 + 2) * 3 + 1]);

Taichi.js (WIP)
---------------

Once you have C source file generated, you can compile them into Javascript
or WASM via Emscripten.

We provide `Taichi.js <https://github.com/taichi-dev/taichi.js>`_ as an
infrastructure for wrapping Taichi kernels for Javascript.
See `its README.md <https://github.com/taichi-dev/taichi.js/blob/master/README.md>`_ for the complete workflow.

Check out `this page <https://taichi-dev.github.io/taichi.js>`_ for online demos.

Calling Taichi kernels from Julia (WIP)
---------------------------------------

Once you have C source generated, you can then compile the C source into a
shared object. Then it can be called from other langurages that provides a C
interface, including but not limited to Julia, Matlab, Mathematica, Java, etc.

TODO: WIP.
18 changes: 9 additions & 9 deletions docs/hello.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ Taichi programs run on either CPUs or GPUs. Initialize Taichi according to your

Supported backends on different platforms:

+----------+------+------+--------+-------+
| platform | CPU | CUDA | OpenGL | Metal |
+==========+======+======+========+=======+
| Windows | OK | OK | OK | N/A |
+----------+------+------+--------+-------+
| Linux | OK | OK | OK | N/A |
+----------+------+------+--------+-------+
| Mac OS X | OK | N/A | N/A | OK |
+----------+------+------+--------+-------+
+----------+------+------+--------+-------+----------+
| platform | CPU | CUDA | OpenGL | Metal | C source |
+==========+======+======+========+=======+==========+
| Windows | OK | OK | OK | N/A | N/A |
+----------+------+------+--------+-------+----------+
| Linux | OK | OK | OK | N/A | OK |
+----------+------+------+--------+-------+----------+
| Mac OS X | OK | N/A | N/A | OK | N/A |
+----------+------+------+--------+-------+----------+

(OK: supported; N/A: not available)

Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ The Taichi Programming Language
faq
gui
debugging
extension_libraries
export_results
cli_utilities
global_settings
export_kernels
extension_libraries
acknowledgments


Expand Down
18 changes: 18 additions & 0 deletions docs/snode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ Taichi provides *Structural Nodes (SNodes)* to compose the hierarchy and particu

* dynamic: Variable-length array, with a predefined maximum length. It serves the role of ``std::vector`` in C++ or ``list`` in Python, and can be used to maintain objects (e.g. particles) contained in a block.

.. note::

Supported SNode types on each backend:

+-----------+----------+--------+-------+----------+
| SNode | CPU/CUDA | OpenGL | Metal | C source |
+===========+==========+========+=======+==========+
| dense | OK | OK | OK | OK |
+-----------+----------+--------+-------+----------+
| bitmasked | OK | N/A | OK | N/A |
+-----------+----------+--------+-------+----------+
| pointer | OK | N/A | N/A | N/A |
+-----------+----------+--------+-------+----------+
| dynamic | OK | PAR | N/A | N/A |
+-----------+----------+--------+-------+----------+

(OK: supported; PAR: partial support; N/A: not available)


See :ref:`layout` for more details. ``ti.root`` is the root node of the data structure.

Expand Down
47 changes: 24 additions & 23 deletions docs/type.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,32 @@ Currently, supported basic types in Taichi are
- float64 ``ti.f64``

.. note::

Supported types on each backend:

+------+-----------+-----------+---------+
| type | CPU/CUDA | OpenGL | Metal |
+======+===========+===========+=========+
| i8 | OK | N/A | OK |
+------+-----------+-----------+---------+
| i16 | OK | N/A | OK |
+------+-----------+-----------+---------+
| i32 | OK | OK | OK |
+------+-----------+-----------+---------+
| i64 | OK | EXT | N/A |
+------+-----------+-----------+---------+
| u8 | OK | N/A | OK |
+------+-----------+-----------+---------+
| u16 | OK | N/A | OK |
+------+-----------+-----------+---------+
| u32 | OK | N/A | OK |
+------+-----------+-----------+---------+
| u64 | OK | N/A | N/A |
+------+-----------+-----------+---------+
| f32 | OK | OK | OK |
+------+-----------+-----------+---------+
| f64 | OK | OK | N/A |
+------+-----------+-----------+---------+
+------+-----------+-----------+---------+----------+
| type | CPU/CUDA | OpenGL | Metal | C source |
+======+===========+===========+=========+==========+
| i8 | OK | N/A | OK | OK |
+------+-----------+-----------+---------+----------+
| i16 | OK | N/A | OK | OK |
+------+-----------+-----------+---------+----------+
| i32 | OK | OK | OK | OK |
+------+-----------+-----------+---------+----------+
| i64 | OK | EXT | N/A | OK |
+------+-----------+-----------+---------+----------+
| u8 | OK | N/A | OK | OK |
+------+-----------+-----------+---------+----------+
| u16 | OK | N/A | OK | OK |
+------+-----------+-----------+---------+----------+
| u32 | OK | N/A | OK | OK |
+------+-----------+-----------+---------+----------+
| u64 | OK | N/A | N/A | OK |
+------+-----------+-----------+---------+----------+
| f32 | OK | OK | OK | OK |
+------+-----------+-----------+---------+----------+
| f64 | OK | OK | N/A | OK |
+------+-----------+-----------+---------+----------+

(OK: supported, EXT: require extension, N/A: not available)

Expand Down
Loading