diff --git a/docs/debugging.rst b/docs/debugging.rst index 3dee6e5f545ae..e7c379a10700d 100644 --- a/docs/debugging.rst +++ b/docs/debugging.rst @@ -144,3 +144,87 @@ For example: def is_odd(x: ti.template()): ti.static_assert(x.data_type() == ti.i32, "is_odd() is only supported for i32") return x % 2 == 1 + + +Tips for debugging +------------------ + +Debugging a Taichi program can be hard even with the builtin tools above. +Taichi developers are currently devoting themselves in improving error messages and warnings +to help user find potential BUGs in their programs. + +Here we collected some common BUGs that one might encounter with a Taichi program: + +Static typing system +++++++++++++++++++++ + +Taichi pertend that it's a dynamical-typed language like Python, but it's actually a +statically-typed language which will be translated into high performance CPU/GPU instructions. + +So the code behavior in Taichi-scope is actually very different from Python-scope! + +Type of a variable is simply **determined at its first initialization and never changes later**. + +Although static-type provides better performance and simplicity, but may leads to BUGs if +users not distinguished Taichi-scope from Python-scope, e.g.: + +.. code-block:: python + + @ti.kernel + def buggy(): + ret = 0 # 0 is a 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 shows 0 + + buggy() + +The codes above shows a common BUG due to the limitation of the static-type system. +The Taichi compiler should shows 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 it can not store a float32 result to int32. +The solution is to type ``ret`` as float32 at the first place: + +.. 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 shows 0.6 + + not_buggy() + + +`@archibate `_'s personal suggestion to prevent issues like this: + +* Recall the ``float ret = 0;`` in C/C++, always use ``ret = float(0)`` on **initialization**, + and ``ret = int(0)`` for integers. So that you are always clear of what type every variable. + +Advanced Optimization ++++++++++++++++++++++ + +Taichi has a advanced optimization engine to make your Taichi kernel to be as fast as it could. +But like the ``gcc -O3`` does, sometimes advanced optimization can leads to BUGs as it tried +too hard, including runtime errors like: + +```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() + + ... + +If that fixed the issue, please report this BUG on `GitHub `_ to help us improve, if you would like to. diff --git a/python/taichi/__init__.py b/python/taichi/__init__.py index 6c9a82c538c11..8cd8c17b36f63 100644 --- a/python/taichi/__init__.py +++ b/python/taichi/__init__.py @@ -7,7 +7,7 @@ from taichi.misc import * from taichi.misc.gui import GUI from taichi.misc.np2ply import PLYWriter -from taichi.misc.image import imread, imwrite, imshow +from taichi.misc.image import * from taichi.misc.task import Task from taichi.misc.test import * from taichi.misc import settings as settings diff --git a/python/taichi/lang/impl.py b/python/taichi/lang/impl.py index 1f2d60488eea8..32ebfc8998564 100644 --- a/python/taichi/lang/impl.py +++ b/python/taichi/lang/impl.py @@ -195,6 +195,9 @@ def get_tape(self, loss=None): def sync(self): self.materialize() self.prog.synchronize() + # print's in kernel won't take effect until ti.sync(), discussion: + # https://github.com/taichi-dev/taichi/pull/1303#discussion_r444897102 + print(taichi_lang_core.pop_python_print_buffer(), end='') pytaichi = PyTaichi() diff --git a/taichi/backends/opengl/opengl_api.cpp b/taichi/backends/opengl/opengl_api.cpp index 1bd9c94590cba..d466d1bc25ae4 100644 --- a/taichi/backends/opengl/opengl_api.cpp +++ b/taichi/backends/opengl/opengl_api.cpp @@ -5,6 +5,7 @@ #include "taichi/program/kernel.h" #include "taichi/program/program.h" #include "taichi/util/environ_config.h" +#include "taichi/python/print_buffer.h" #include "taichi/backends/opengl/runtime.h" #ifdef TI_WITH_OPENGL @@ -487,7 +488,7 @@ struct CompiledProgram::Impl { TI_WARN("[glsl] Unexpected serialization type: {}, ignoring", type); break; }; - std::cout << str; + py_cout << str; } } rt_buf->msg_count = 0; diff --git a/taichi/python/export_misc.cpp b/taichi/python/export_misc.cpp index 2c3c250692b6b..e48a3b8fb9d7c 100644 --- a/taichi/python/export_misc.cpp +++ b/taichi/python/export_misc.cpp @@ -7,6 +7,7 @@ #include "taichi/common/task.h" #include "taichi/math/math.h" #include "taichi/python/exception.h" +#include "taichi/python/print_buffer.h" #include "taichi/python/export.h" #include "taichi/system/benchmark.h" #include "taichi/system/profiler.h" @@ -20,6 +21,8 @@ TI_NAMESPACE_BEGIN +PythonPrintBuffer py_cout; + Config config_from_py_dict(py::dict &c) { Config config; for (auto item : c) { @@ -153,6 +156,9 @@ void export_misc(py::module &m) { } printf("test was successful.\n"); }); + m.def("pop_python_print_buffer", []() { + return py_cout.pop_content(); + }); m.def("with_cuda", is_cuda_api_available); m.def("with_metal", taichi::lang::metal::is_metal_api_available); m.def("with_opengl", taichi::lang::opengl::is_opengl_api_available); diff --git a/taichi/python/print_buffer.h b/taichi/python/print_buffer.h new file mode 100644 index 0000000000000..857990cc04e50 --- /dev/null +++ b/taichi/python/print_buffer.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +TI_NAMESPACE_BEGIN + +struct PythonPrintBuffer { + /* holds kernel print result before switching back to python */ + std::stringstream ss; + + template + PythonPrintBuffer &operator<<(const T &t) { + ss << t; + return *this; + } + std::string pop_content() { + auto ret = ss.str(); + ss = std::stringstream(); + return ret; + } +}; + +extern PythonPrintBuffer py_cout; + +TI_NAMESPACE_END