-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Lang] Add ti.static_assert for compile-time assertations (#1344)
* [Lang] Add ti.static_assert for compile-time assertations * add index * [skip ci] Apply suggestions from code review Co-authored-by: Danni <[email protected]> Co-authored-by: Xudong Feng <[email protected]> * [skip ci] enforce code format * [skip ci] Apply suggestions from code review Co-authored-by: Yuanming Hu <[email protected]> Co-authored-by: Xudong Feng <[email protected]> Co-authored-by: Danni <[email protected]> * [skip ci] revert ti.chain_compare * [skip ci] enforce code format * [skip ci] update bug_report.md * [skip ci] Apply suggestions from code review Co-authored-by: Yuanming Hu <[email protected]> * [skip ci] Update docs/debugging.rst Co-authored-by: Yuanming Hu <[email protected]> * add func desc * Apply suggestions from code review Co-authored-by: Danni <[email protected]> Co-authored-by: Yuanming Hu <[email protected]> * well @ti.pyfunc * Apply suggestions from code review Co-authored-by: Danni <[email protected]> * [skip ci] Apply suggestions from code review Co-authored-by: Yuanming Hu <[email protected]> * Update tests/python/test_assert.py Co-authored-by: Danni <[email protected]> Co-authored-by: Xudong Feng <[email protected]> Co-authored-by: Taichi Gardener <[email protected]> Co-authored-by: Yuanming Hu <[email protected]>
- Loading branch information
1 parent
95ac7c5
commit eb40824
Showing
6 changed files
with
298 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
Debugging | ||
========= | ||
|
||
Debugging a parallel program is not easy, so Taichi provides | ||
builtin utilities that could hopefully help you debug your Taichi program. | ||
|
||
Run-time ``print`` in kernels | ||
----------------------------- | ||
|
||
.. function:: print(arg1, ..., sep=' ', end='\n') | ||
|
||
Debug your program with ``print()`` in Taichi-scope. For example: | ||
|
||
.. code-block:: python | ||
@ti.kernel | ||
def inside_taichi_scope(): | ||
x = 233 | ||
print('hello', x) | ||
#=> hello 233 | ||
print('hello', x * 2 + 200) | ||
#=> hello 666 | ||
print('hello', x, sep='') | ||
#=> hello233 | ||
print('hello', x, sep='', end='') | ||
print('world', x, sep='') | ||
#=> hello233world233 | ||
m = ti.Matrix([[2, 3, 4], [5, 6, 7]]) | ||
print('m =', m) | ||
#=> m = [[2, 3, 4], [5, 6, 7]] | ||
v = ti.Vector([3, 4]) | ||
print('v =', v) | ||
#=> v = [3, 4] | ||
For now, Taichi-scope ``print`` supports string, scalar, vector, and matrix expressions as arguments. | ||
``print`` in Taichi-scope may be a little different from ``print`` in Python-scope. Please see details below. | ||
|
||
.. warning:: | ||
|
||
For the **CPU, CUDA, and Metal backend**, ``print`` will not work in Graphical Python Shells | ||
including IDLE and Jupyter notebook. This is because these backends print the outputs to the console instead of the GUI. | ||
Taichi developers are trying to solve this now. Use the **OpenGL backend** if you wish to | ||
use ``print`` in IDLE / Jupyter. | ||
|
||
.. warning:: | ||
|
||
Note that ``print`` in Taichi-scope can only receive **comma-separated parameter**. Neither f-string nor formatted string should be used. For example: | ||
.. code-block:: python | ||
import taichi as ti | ||
ti.init(arch=ti.cpu) | ||
a = ti.var(ti.f32, 4) | ||
@ti.kernel | ||
def foo(): | ||
a[0] = 1.0 | ||
print('a[0] = ', a[0]) # right | ||
print(f'a[0] = {a[0]}') # wrong, f-string is not supported | ||
print("a[0] = %f" % a[0]) # wrong, formatted string is not supported | ||
foo() | ||
.. note:: | ||
|
||
For the **OpenGL and CUDA backend**, the printed result will not show up until ``ti.sync()`` is called: | ||
|
||
.. code-block:: python | ||
import taichi as ti | ||
ti.init(arch=ti.cuda) | ||
@ti.kernel | ||
def kern(): | ||
print('inside kernel') | ||
print('before kernel') | ||
kern() | ||
print('after kernel') | ||
ti.sync() | ||
print('after sync') | ||
obtains: | ||
|
||
.. code-block:: none | ||
before kernel | ||
after kernel | ||
inside kernel | ||
after | ||
Please note that host access or program end will also implicitly invoke ``ti.sync()``. | ||
|
||
|
||
Compile-time ``ti.static_print`` | ||
-------------------------------- | ||
|
||
Sometimes it is useful to print Python-scope objects and constants like data types or SNodes in Taichi-scope. | ||
So, similar to ``ti.static`` we provide ``ti.static_print`` to print compile-time constants. | ||
It is similar to Python-scope ``print``. | ||
|
||
.. code-block:: python | ||
x = ti.var(ti.f32, (2, 3)) | ||
y = 1 | ||
@ti.kernel | ||
def inside_taichi_scope(): | ||
ti.static_print(y) | ||
# => 1 | ||
ti.static_print(x.shape) | ||
# => (2, 3) | ||
ti.static_print(x.dtype) | ||
# => DataType.float32 | ||
for i in range(4): | ||
ti.static_print(i.dtype) | ||
# => DataType.int32 | ||
# will only print once | ||
Unlike ``print``, ``ti.static_print`` will only print the expression once at compile-time, and | ||
therefore it has no runtime cost. | ||
|
||
|
||
Runtime ``assert`` in kernel | ||
---------------------------- | ||
|
||
Programmers may use ``assert`` statements in Taichi-scope. When the assertion condition failed, a | ||
``RuntimeError`` will be raised to indicate the error. | ||
|
||
To make ``assert`` work, first make sure you are using the **CPU backend**. | ||
For performance reason, ``assert`` only works when ``debug`` mode is on, For example: | ||
|
||
.. code-block:: python | ||
ti.init(arch=ti.cpu, debug=True) | ||
x = ti.var(ti.f32, 128) | ||
@ti.kernel | ||
def do_sqrt_all(): | ||
for i in x: | ||
assert x[i] >= 0 | ||
x[i] = ti.sqrt(x) | ||
When you are done with debugging, simply set ``debug=False``. Now ``assert`` will be ignored | ||
and there will be no runtime overhead. | ||
|
||
|
||
Compile-time ``ti.static_assert`` | ||
--------------------------------- | ||
|
||
.. function:: ti.static_assert(cond, msg=None) | ||
|
||
Like ``ti.static_print``, we also provide a static version of ``assert``: | ||
``ti.static_assert``. It can be useful to make assertions on data types, dimensionality, and shapes. | ||
It works whether ``debug=True`` is specified or not. When an assertion fails, it will | ||
raise an ``AssertionError``, just like a Python-scope ``assert``. | ||
|
||
For example: | ||
|
||
.. code-block:: python | ||
@ti.func | ||
def copy(dst: ti.template(), src: ti.template()): | ||
ti.static_assert(dst.shape == src.shape, "copy() needs src and dst tensors to be same shape") | ||
for I in ti.grouped(src): | ||
dst[I] = src[I] | ||
return x % 2 == 1 | ||
Debugging Tips | ||
-------------- | ||
|
||
Debugging a Taichi program can be hard even with the builtin tools above. | ||
Here we showcase some common bugs that one may encounter in a Taichi program. | ||
|
||
Static type system | ||
++++++++++++++++++ | ||
|
||
Python code in Taichi-scope is translated into a statically typed language for high performance. This means code in Taichi-scope can have a different behavior compared with that in Python-scope, especially when it comes to types. | ||
|
||
The type of a variable is simply **determined at its initialization and never changes later**. | ||
|
||
Although Taichi's static type system provides better performance, it may lead to bugs if | ||
programmers carelessly used the wrong types. For example, | ||
|
||
.. code-block:: python | ||
@ti.kernel | ||
def buggy(): | ||
ret = 0 # 0 is an integer, so `ret` is typed as int32 | ||
for i in range(3): | ||
ret += 0.1 * i # i32 += f32, the result is still stored in int32! | ||
print(ret) # will show 0 | ||
buggy() | ||
The code above shows a common bug due to Taichi's static type system. | ||
The Taichi compiler should show a warning like: | ||
|
||
.. code-block:: none | ||
[W 06/27/20 21:43:51.853] [type_check.cpp:visit@66] [$19] Atomic add (float32 to int32) may lose precision. | ||
This means that Taichi cannot store a ``float32`` result precisely to ``int32``. | ||
The solution is to initialize ``ret`` as a float-point value: | ||
|
||
.. code-block:: python | ||
@ti.kernel | ||
def not_buggy(): | ||
ret = 0.0 # 0 is a floating point number, so `ret` is typed as float32 | ||
for i in range(3): | ||
ret += 0.1 * i # f32 += f32. OK! | ||
print(ret) # will show 0.6 | ||
not_buggy() | ||
Advanced Optimization | ||
+++++++++++++++++++++ | ||
|
||
Taichi has an advanced optimization engine to make your Taichi kernel to be as fast as it could. | ||
But like what ``gcc -O3`` does, advanced optimization may occasionally lead to bugs as it tries | ||
too hard. This includes runtime errors such as: | ||
|
||
```RuntimeError: [verify.cpp:basic_verify@40] stmt 8 cannot have operand 7.``` | ||
|
||
You may use ``ti.core.toggle_advance_optimization(False)`` to turn off advanced | ||
optimization and see if the issue still exists: | ||
|
||
.. code-block:: python | ||
import taichi as ti | ||
ti.init() | ||
ti.core.toggle_advance_optimization(False) | ||
... | ||
If turning off optimization fixes the issue, please report this bug on `GitHub <https://github.com/taichi-dev/taichi/issues/new?labels=potential+bug&template=bug_report.md>`_. Thank you! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters