开发与贡献指南¶
首先,感谢你的参与和贡献!我们欢迎一切形式的贡献,包括但不限于
- 修复 BUG
- 提出和实现新功能
- 对本文档进行改进和翻译(欢迎前往 Taichi 中文文档)
- 完善错误时的提示,使之对用户更友好
- 提交新的测试用例
- 提交新的样例程序
- 提交编译器性能补丁
- 发布有关 Taichi 的博客文章和教程
- 加入我们的 Taichi 论坛
- 向你的朋友们介绍 Taichi 或者直接在 GitHub 上星标 Taichi 也可以。
- 修复文档,代码,注释中的拼写错误(像这样的小问题请直接创建一个 PR 而不必开一个 issue)
如何参与 BUG 修复,添加新特性¶
标记了 “good first issue” 的 issue 是较容易上手的。
- 请先在这个 issue 中留下一句评论(比如: 我知道怎么解决这个,我乐意帮忙! )。这样大家就知道已经有人在解决这个问题了,从而避免重复劳动;
- 如果没有核心开发成员说明一个 issue 可能的解决方案,请简要地描述你的方案,并在你开始之前静候开发成员的回复,从而保障实现的简洁高效。
标记了 “welcome contribution” 的 issue 相比之下更有挑战性但对新手仍然是比较友好的。
进阶指导¶
- 切实解决问题是我们的最终目标。
- 不要小题大做:用 简单 的方案去解决简单的问题,这样你可以抽出时间和精力处理那些真正困难的问题。
- 几乎每一个设计都有两面性。如果利大于弊,那就可以看作是一个 好的决定 ,请务必权衡利弊。
- 调试是很困难的,每一次的改动应该很小,这样 BUG 的源头就可以很容易地找到。
- 单元/集成测试是我们的好伙伴。
注解
“软件设计过程中中存在两种模式:一种是使之结构简单明了到没有任何问题,另一种是令结构设计足够复杂到完美无缺 而第一种方案则要困难的多.” — C.A.R. 霍尔
需要记住的一点是,Taichi 最初作为一个学术研究项目而诞生。这通常意味着有些部分没有机会经过稳固坚实的设计。虽然我们一直在努力提高代码质量,但这并不意味着项目能没有技术负债。有些地方仍可能会过于复杂而让人感到困惑。一旦你发现这种情形的存在,非常欢迎给我们提出 PR!:-)
高效率地沟通¶
- 传达了多少有效信息,比打了多少字重要的多。
- 在沟通中保持积极,礼貌,注意语言的组织性、准确性。
- 注意除了文字之外,列表(Bulleted lists)也是我们表达过程中的好伙伴。
- 提交评论前请仔细预读:如果你是读者,你能读懂自己所写的内容么?
- 如果你的母语不是英语,考虑使用拼写检查器,如 Grammarly 。
请根据事实进行讨论与反馈,而不是个人感觉。对我们所有人来说,保持一个友好、零责备的社区环境是非常重要的。一些例子如下:
小技巧
(可接受的表达方式)这种设计可能会让 Taichi 的初学者感到困惑。
警告
(不可接受的表达方式)这种设计真是太糟糕了。
提交良好的 PR¶
- 我们鼓励改动很小的 PR, 一个 PR 理想情况下应该 只针对一个问题(issue) 。
- 也可以掺杂一些 无关紧要 的优化重构,比如修正笔误;
- 审稿人保留要求 PR 作者删除一些 无关紧要 的改动的权利。
- PR 中的所有 commit 都应被 压缩&合并到 master 分支的一个 commit 里 。
- 为保留清晰的提交日志 PR 作者 不应该将多条 commit 压缩(squash)后提交;
- 当实现一个复杂的特性时,考虑将其分散为许多个小 PR,从而保证更具细节的开发时间线,保证与开发者更频繁的沟通。
- 如果你想更及时的得到核心开发成员的反馈
- 通过 GitHub 的 Draft 状态开一个 PR,这样就可以和我们实时分享你的进展了;
- 请确保在评论中 @ 相应开发成员,或者使用请求评审(request the review)。
- 如果你同时在处理多个 PR
- 互不依赖的 PR 都应该是基于
master衍生出的 不同 分支; - 互相依赖的 PR 应该在所有前置 PR 合并入
master后再进行提出。
- 互不依赖的 PR 都应该是基于
- 所有 PR 理想情况下都应该伴随着相应的 测试;
- 除了内部编译器的实现外,其余的 PR 都应该带有与其功能相对应的 文档更新(documentation update);
- 所有 PR 必须通过 持续集成测试(continuous integration tests) 后才能被合并;
- PR 的标题应当按照 PR title format and tags 的要求编写;
- 除此之外,谷歌有篇相当棒的文章 how to have your PR merged quickly. [PDF] 可供参考
审核与 PR 的合并¶
- 请按照以下几个来自谷歌的建议
- 合并操作应当始终将 PR 压缩&合并 到主分支(默认为master)上;
- 主分支要求记录 线性历史;
- 确保 PR 能够顺利通过 持续集成测试,文档更新等情况除外;
- 确保标题遵循 PR title format and tags 的要求。
持续集成的运用¶
规范代码结构¶
在本地,可以通过在命令行中运行
ti format来自动格式化代码。请注意,在使用ti format之前,您必须在本地安装clang-format-6.0和yapf v0.29.0。如果不想在本地安装这些格式化工具,也可以使用 格式化服务器(format server) 。这是个
ti format的在线版本。- 访问 http://kun.csail.mit.edu:31415/,并点击选取所需格式化的 PR id。
- 回到 PR 页面,你将看到一个名为 @taichi-gardener (机器人) 的用户推送了一个名为
[skip ci] enforce code format的提交。 - 如果你没能找到机器人的提交,说明没有发现任何不规范的代码格式,。
- 然后在本地分支中运行
git pull来提取格式化代码。 - 值得留意的是,备注带有为
[format]的提交信息将自动触发格式化服务。例如:[format] our commit message
PR 标题格式和标签¶
PR 标题将成为 master 分支中提交历史的一部分,因此保证 PR 标题的可读性非常重要。
请务必在 PR 标题前附加上至少一个标签,如
[Metal]等:
- 当使用多个标签时,确保标签之间只留有一个空格分隔;
- 例如,
[Metal][refactor]``(没有空格)应该被格式化为 ``[Metal] [refactor];PR 标题主干部分的首字母应该大写:
- 例如,
[doc] improve documentation应该被格式化为[doc] Improve documentation;- 同时,
[Lang] “ti.sqr(x)” is now deprecated是可以的,因为“是一个符号。请不要在 PR 标题中包括反引号 (“`”)。
例如,“[Metal] Support bitmasked SNode”,“[OpenGL] AtomicMin/Max support”,或 “[Opt] [IR] Enhanced constant folding”。
常用的标签:
[Metal], [OpenGL], [CPU], [CUDA]: backends;[LLVM]: CPU 和 CUDA 共享的 LLVM 后端;[Lang]: 前端语法特性,包括语法糖;[Std]: 标准库,例如ti.Matrix和ti.Vector;[IR]: 中间表示(intermediate representation, IR);[Opt]: IR 优化迭代轮数;[GUI]: 内嵌的 GUI 系统;[Refactor]: 代码重构优化;[CLI]: 命令行接口, 例如ti命令;[Doc]: 与docs/目录下的文档相关;[Example]: 与examples/目录下的样例程序相关;[Test]: 与tests/目录下增加和改进测试程序相关;[Linux]: 与Linux 平台有关;[Mac]: 与Mac OS X 平台有关;[Windows]: 与Windows 平台有关;[Perf]: 性能改进;[Misc]: 难以归类的杂项,如版本跳跃,格式优化;[Bug]: 修复 Bug;- 在 misc/prtags.json 中查看更多标签.
- 在引进新标签时,请在首先使用该标签的 PR 中一并更新
misc/prtags.json列表,以便其余成员跟随使用。
注解
我们感谢所有的贡献,但是我们不应该把每一个 PR 的标题暴露给终端用户。因此,应该将变更日志分类成 用户应该知道什么 和 开发人员正在做什么 是必要的。而这是通过 大写 PR 标签 区分的:
- 对用户可见/值得注意的 PR,应该将其一开始的标签以 大写的首字母 进行标记,例如
[Metal], [OpenGL], [IR], [Lang], [CLI]。在发布新版本时,脚本(python/taichi/make_changelog.py)将生成一个突出显示这些更改(PR 标题)的变更日志。因此,确保终端用户能够理解你的 PR 所做的工作是非常 重要 的,而这都是 基于你的PR标题。- 其他类型的 PR(底层开发/中间实现)应该使用 全小写字母 的标签 :例如
[metal], [opengl], [ir], [lang], [cli]。- 由于发布更新日志的生成方式,PR 标题中应该 最多只有一个大写标记,以防止重复的 PR 突出显示。例如,
[GUI] [Mac] Support modifier keys(#1189) 就是一个反例, 我们应该用[gui] [Mac] Support modifier keys in GUI来替代。 请只大写与 PR 内容最相关的标签。
C++ 和 Python 标准¶
Taichi 的 C++ 模块是基于 C++ 17编写的,Python 模块是基于3.6+编写的。所以你可以合理认为 C++ 17和 Python 3.6 特性总是可用的。
Taichi 编译器的开发建议¶
阅读 Life of a Taichi kernel 这一章也许有助于你理解我们的工作。它解释了整个编译过程。
如果你的工作涉及 IR 优化,请参见 基准测试和回归测试 。
使用 ti.init(arch=desired_arch, **kwargs) 创建 Taichi 程序时,传入以下参数,可以使 Taichi 编译器打印出 IR:
print_preprocessed = True:打印前端 Python AST 转换的结果。结果脚本(resulting scripts)在执行时将生成一个 Taichi 前端 AST。print_ir = True:打印内核编译(不包括访问器)中的 Taichi IR 转换过程。print_accessor_ir = True:打印数据访问器的 IR 转换过程,这是一种特殊而简单的内核信息。(不过很少使用,除非你正在调试数据访问器相关的编译)print_struct_llvm_ir = True: 保存由 Taichi 结构编译器生成的 LLVM IR。print_kernel_llvm_ir = True: 保存由 Taichi 内核编译器生成的 LLVM IR。print_kernel_llvm_ir_optimized = True:保存每个内核优化的 LLVM IR。print_kernel_nvptx = True:保存每个内核生成的 NVPTX(仅限 CUDA)。
注解
Python 作用域中的数据访问器被实现为特殊的 Taichi 内核。例如,x[1, 2, 3] = 3 将调用 x 的写访问器内核, print(y[42]) 将调用 y 的读访问器内核。
目录结构¶
关键文件包括
taichi: 核心编译器实现program: 上层结构ir: 中间表示analysis: 静态分析transforms: IR 转换传递(Passes)inc: Small definition files to be included repeatedlyjit: Just-In-Time compilation base classesllvm: LLVM utilitiesruntime: LLVM runtime environmentsstruct: 结构编译器基类codegen: 代码生成基类backends: 基于设备的代码生成/运行时环境cpu: CPU backend implementationcuda: CUDA backend implementationopengl: OpenGL backend implementationmetal: Metal backend implementationcc: C backend implementation (WIP)
gui: GUI systemmath: Math utilitiespython: C++/Python 接口platform: 平台支持依赖system: 操作系统相关的基础结构util: 各种各样的工具
python/taichi: Python frontend implementationcore: Loading & interacting with Taichi corelang: Python-embbed Taichi language & syntax (major)misc: Miscellaneous utilitiestools: Handy end-user tools
tests: Functional testspython: Python tests (major)cpp: C++ tests
examples: 样例程序docs: 文档benchmarks: 性能基准external: External librariesmisc: 零散(但仍很有用)的文件…
测试¶
Tests should be added to tests/.
Command line tools¶
- 通过使用
ti test运行所有测试实例。 - 通过使用
ti test -v查看详细输出信息。 - 通过使用
ti test -C运行测试并记录代码覆盖率, 参阅 Code coverage 查看更多信息. - Use
ti test -a <arch(s)>for testing against specified backend(s). e.g.ti test -a cuda,metal. - Use
ti test -na <arch(s)>for testing all architectures excluding some of them. e.g.ti test -na opengl,x64. - Use
ti test <filename(s)>to run specific tests in filenames. e.g.ti test numpy_iowill run all tests intests/python/test_numpy_io.py. - Use
ti test -cto run only the C++ tests. e.g.ti test -c alg_simpwill runtests/cpp/test_alg_simp.cpp. - Use
ti test -k <key>to run tests that match the specified key. e.g.ti test linalg -k "cross or diag"will run thetest_crossandtest_diagintests/python/test_linalg.py.
或者使用 ti test -h 查看更多选项。
For more details on how to write a test case, see write_test.
文档¶
Documentations are put under the folder docs/.
- We use reStructured text (.rst) to write documentation.
- We host our documentation online using readthedocs.io.
- 使用
ti doc建立本地文档。 - Open the documentation at
docs/build/index.html.
注解
在 Linux/OS X 下, 使用 watch -n 1 ti doc 以持续地构建文档。
如果 OpenGL 后端检测器一直在创建新窗口,对 ti doc 附加执行 export TI_WITH_OPENGL=0 。
升级 CUDA¶
目前我们的开发工作是针对 CUDA 10。在升级 CUDA 版本时,当前 external/cuda_libdevice/slim_libdevice.10.bc 文件应该被新的版本的所取代。
To generate the slimmed version of libdevice based on a full libdevice.X.bc file from a CUDA installation,
use ti task make_slim_libdevice [libdevice.X.bc file]