1<!-- mdformat off(b/169948621#comment2) -->
2
3<!-- Define reference-style links used throughout the document -->
4[small PRs]: https://google.github.io/eng-practices/review/developer/small-cls.html
5[Micro Contributing Guidelines]: https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/CONTRIBUTING.md
6[Providing Context]: https://testing.googleblog.com/2017/09/code-health-providing-context-with.html
7[`ParseOpDataTfLite()`]: https://github.com/tensorflow/tensorflow/blob/d8394a6d774f5e3c02d97f1fc18ff445199db598/tensorflow/lite/core/api/flatbuffer_conversions.cc#L135
8[PR #45307]: https://github.com/tensorflow/tensorflow/pull/45307
9[PR #46021]: https://github.com/tensorflow/tensorflow/pull/46021
10[PR #45311]: https://github.com/tensorflow/tensorflow/pull/45311
11[PR #45457]: https://github.com/tensorflow/tensorflow/pull/45457
12[PR #45646]: https://github.com/tensorflow/tensorflow/pull/45646
13[PR #45647]: https://github.com/tensorflow/tensorflow/pull/45647
14[pre-submit checklist]: https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/CONTRIBUTING.md#before-submitting-your-pr
15[reference_ops.h]: https://github.com/tensorflow/tensorflow/blob/92f459e6b917fa5099ef5317d14c5100d33a86f0/tensorflow/lite/kernels/internal/reference/reference_ops.h
16[general porting guidelines]: #general-porting-guidelines
17
18# Porting Reference Ops from Lite to Micro
19
20This is a guide to porting reference ops from Lite to Micro. It explains,
21step-by-step, the recommended code changes and the process for submitting them
22for review and acceptance.  The process results in multiple pull requests, or
23PRs. Multiple, [small PRs][] are easier for the project to review and merge.
24
25The [Micro Contributing Guidelines][] are prerequisite reading. They cover
26general code health, maintainability, style, and submission, as well as how to
27setup a development environment. This guide contains step-by-step instructions
28for the specific task of porting reference ops from Lite to Micro.
29
30<!--
31Semi-automated TOC generation with instructions from
32https://github.com/ekalinin/github-markdown-toc#auto-insert-and-update-toc
33-->
34<!--ts-->
35* [Porting Reference Ops from Lite to Micro](#porting-reference-ops-from-lite-to-micro)
36   * [1. Look for a port already in progress](#1-look-for-a-port-already-in-progress)
37   * [2. Open a GitHub issue to track the port](#2-open-a-github-issue-to-track-the-port)
38   * [3. Extract Lite's code for parsing op parameters to a function (PR1)](#3-extract-lites-code-for-parsing-op-parameters-to-a-function-pr1)
39   * [4. Extract the reference for the op to a standalone header (PR2)](#4-extract-the-reference-for-the-op-to-a-standalone-header-pr2)
40   * [5. Port the op from Lite to Micro (PR3)](#5-port-the-op-from-lite-to-micro-pr3)
41* [General Guidelines](#general-guidelines)
42   * [Check each commit for formatting, lint, and unit-test passage](#check-each-commit-for-formatting-lint-and-unit-test-passage)
43   * [Add yourself as an asignee to PRs](#add-yourself-as-an-asignee-to-prs)
44   * [Maintain a 1:1 correspondence between Micro and Lite versions of unit tests](#maintain-a-11-correspondence-between-micro-and-lite-versions-of-unit-tests)
45   * [Sometimes CI checks on PRs are flakey and fail](#sometimes-ci-checks-on-prs-are-flakey-and-fail)
46* [Notes](#notes)
47
48<!-- Added by: rkuester, at: Wed 05 May 2021 07:44:11 PM CDT -->
49
50<!--te-->
51
52## 1. Look for a port already in progress
53
54Begin by searching the TensorFlow GitHub repository for issues containing the
55name of the op under consideration to ensure someone isn't already working on a
56port.
57
58## 2. Open a GitHub issue to track the port
59
60Open a GitHub issue to announce your intent to port the op, and to begin a
61record of your work. Document the entire process of porting the op in this
62issue. Link constituent PRs to this issue. See the article [Providing
63Context][] for background on documenting your work via bug reports.
64
65A good example is [issue #45306: micro: port op FILL from lite](https://github.com/tensorflow/tensorflow/issues/45306).
66
67## 3. Extract Lite's code for parsing op parameters to a function (PR1)
68
69Now we begin changing, testing, and submitting code. This step will result in
70the first pull request, PR1.
71
721.  Extract the code for parsing op parameters out of the switch statement in
73    [`ParseOpDataTfLite()`][] in `lite/core/api/flatbuffer_conversions.cc` into
74    a standalone function, and call that function from the switch statement.
75    This standalone function is now available to be called by the Micro op
76    resolver, which also needs to parse the op parameters, in a future change.
77    A simple example is [PR #45307][], and a more complicated example is [PR
78    #46021][].
79
801.  Use `clang-format` to make sure the code is properly formatted.
81
82    ```shell
83    clang-format --style=google -i $(git ls-files -m | grep -E '\.cc|\.h')
84    ```
85
861.  Make sure your code is lint-free.
87
88    ```shell
89    cpplint.py $(git ls-files -m)
90    ```
91
921.  Create a single commit containing the change. Observe the guidelines for
93    good commit log messages found in the article [Providing Context][].
94    A good example is commit [0664214](https://github.com/tensorflow/tensorflow/pull/45307/commits/0664214792ad2357f6224e7002661894775cb512).
95
961.  Since this change modifies the op's implementation in Lite, test the change
97    with the relevant Lite unit tests.
98
99    ```shell
100    bazel test tensorflow/lite/kernels:all
101    ```
102
1031.  Create and submit the PR. Write a [good PR description][], and be sure to
104    link to the GitHub issue created to document the port. A good example is
105    [PR #45307][].
106
107    [good PR description]: https://google.github.io/eng-practices/review/developer/cl-descriptions.html
108
109## 4. Extract the reference for the op to a standalone header (PR2)
110
111Move the reference implementation of the op in [reference_ops.h][] to a standalone header so that
112Micro can include it without including unrelated dependencies via
113reference_ops.h.
114
115A good example is [PR #45311][].
116
1171.  Copy an existing header from `tensorflow/lite/kernels/internal/reference/`
118    to `tensorflow/lite/kernels/internal/reference/NEW_OP.H` to create the
119    boilerplate. Replace `NEW_OP.H` with the name of the new operator.
120
1211.  Move the implementation from
122    `tensorflow/lite/kernels/internal/reference/reference_ops.h` to
123    `tensorflow/lite/kernels/internal/reference/NEW_OP.H`.
124
1251.  Add the new header to the build by adding to the  library definitions
126    `reference_base` and `legacy_reference_base` in the file
127    `tensorflow/lite/kernels/internal/BUILD`. See, for example,
128    [this change for operator FILL](https://github.com/tensorflow/tensorflow/pull/45311/commits/92f459e6b917fa5099ef5317d14c5100d33a86f0#diff-0b0fc9e1affece3c5a141ee9326f882876b6b958bc8b12a7c01d7540dc04983e).
129
1301.  Use the program `clang-format` to make sure the code is properly formatted.
131
132    ```shell
133    clang-format --style=google -i $(git ls-files -m | grep -E '\.cc|\.h')
134    ```
135
136    Do not clang-format existing code in `BUILD` or `reference_ops.h`.
137
1381.  Make sure your code is lint-free.
139
140    ```shell
141    cpplint.py $(git ls-files -m)
142    ```
143
144    Do not modify code in `BUILD` or `reference_ops.h` to satisfy `cpplint.py`.
145
1461.  Create a single commit containing the change. Observe the guidelines for
147    good commit log messages found in the article [Providing Context][].
148    A good example is commit [92f459e](https://github.com/tensorflow/tensorflow/commit/92f459e6b917fa5099ef5317d14c5100d33a86f0).
149
1501.  Since this change modifies the op's implementation in Lite, test the change
151    with the relevant Lite unit tests.
152
153    ```shell
154    bazel test tensorflow/lite/kernels:all
155    ```
156
1571.  Create and submit the PR. Write a [good PR description][], and be sure to
158    link to the GitHub issue created to document the port. A good example is
159    [PR #45311][].
160
161## 5. Port the op from Lite to Micro (PR3)
162
1631.  Copy the kernel and test from Lite to Micro.
164
165    In the first commit of this PR, copy the kernel and test from Lite to Micro
166    without making any modifications and without adding them to the build.
167
168    A good example is commit [a2ca1fd](https://github.com/tensorflow/tensorflow/commit/a2ca1fd7a174438f736c0435dd3e4e618612fdee).
169
170    This copy action is in its own commit in order to create readable, reviewable diffs
171    when modifications are made in later commits. If the files were copied and
172    modified in one step, the modifications would not appear as a diff of the Lite
173    version. Instead, the files would simply appear at the destination path in
174    their final form.
175
176
1771.  Remove Lite-specific code from copies
178
179    In the second commit of this PR, remove the bulk of Lite-specific code from
180    the files copied to micro in the previous step.
181
182    A good example is commit [a5a87b4](https://github.com/tensorflow/tensorflow/commit/a5a87b420b87a1f832e241db3a5b724207ea700a).
183
184    This bulk-delete action is in its own commit for reasons similar to
185    those given in the step above: to produce a more readable, reviewable diff in this
186    step and in the next. Because the files are not yet added to the build, they
187    need not (and obviously won't) compiler or function. What to delete now as
188    opposed to deleting in the next commit is somewhat subjective, but make
189    deletes in order to:
190
191    -   Flatten the namespace down to `tflite`.
192    -   Stop resizing output tensors.
193    -   Remove input and output types other than `int8` and `float32`.
194    -   Stop using gmock and gtest.
195    -   etc.
196
1971.  Port the op and the test
198
199    Make the necessary changes to the micro kernel, header, and test to make the op
200    implementation suitable for micro. Include these in the build.
201
202    This step requires the most creativity, and may receive the most feedback
203    during review. Maintain good atomicity in your commits. Considering its
204    scope, this step will consist of more than one commit. A good example is
205    the changes made in [PR #45647][].
206
2071.  Use `clang-format` to make sure the code is properly formatted.
208
209    ```shell
210    $ clang-format --style=google -i $(git ls-files -m | grep -E '\.cc|\.h')
211    ```
212
213    Do not clang-format existing code in `BUILD` or `reference_ops.h`.
214
2151.  Make sure the code is lint-free.
216
217    ```shell
218    $ cpplint.py $(git ls-files -m)
219    ```
220
221    Do not modify code in `BUILD` or `reference_ops.h` to satisfy `cpplint.py`.
222
2231.  Make sure the port passes all applicable tests.
224
225    ```shell
226    $ bazel test tensorflow/lite/micro/kernels:${op}_test
227    $ bazel test tensorflow/lite/micro/kernels:all
228    $ make -f tensorflow/lite/micro/tools/make/Makefile test_kernel_${op}_test
229    $ make -f tensorflow/lite/micro/tools/make/Makefile test
230    ```
231
232    See the general [Micro Contributing Guidelines][] for other testing ideas,
233    including the use of address sanitizers.
234
2351.  Create and submit the PR. Write a [good PR description][], and be sure to
236    link to the GitHub issue created to document the port. A good example is
237    [PR #45647][].
238
239# General Guidelines
240
241## Check each commit for formatting, lint, and unit-test passage
242
243Check each commit against the [pre-submit checklist][] in the micro
244Contributing Guidelines. Specifically, make sure your code:
245
2461.  Is formatted with clang-format.
2471.  Passes a lint check.
2481.  Passes all unit tests.
249
250    ```shell
251    $ make -s -j8 -f tensorflow/lite/micro/tools/make/Makefile test
252    ```
253
254CI runs these checks on all PRs, and will hold up your PR if any of these checks fail.
255
256## Add yourself as an asignee to PRs
257
258Feel free to add yourself as an additional assignee to PRs which you submit.
259Other assignees may be set by the project's various bots.
260
261## Maintain a 1:1 correspondence between Micro and Lite versions of unit tests
262
263To the extent possible, maintain a 1:1 correspondence between Micro and Lite
264versions of unit tests. Avoid cleanup of merely stylistic issues, e.g., by
265replacing the hardcoded literal `3.40282e+038` with
266`std::numeric_limits<float>::max()`. Any changes between the Micro and Lite
267versions of a test put a burden on future maintainers to figure out whether the
268differences are actually significant or just stylistic.
269
270## Sometimes CI checks on PRs are flakey and fail
271
272Sometimes CI checks on PRs don't fail because of the PRs contents, but because
273of some problem with the test infrastructure. Marking issues with the label
274`kokoro:force-run` causes the checks to be rerun.
275
276# Notes
277
278*   There was discussion of commits vs. PRs in [#45387](https://github.com/tensorflow/tensorflow/issues/45387).
279
280*   On Debian, running bazel required installing package bazel-3.1.0.
281
282*   If you have permission, add the label `comp:micro` to these PRs.
283
284*   If you have permission, the label `kokoro:force-run` can be applied to
285    manually trigger the CI builds.
286
287*   [TensorFlow Lite 8-bit quantization specification](https://www.tensorflow.org/lite/performance/quantization_spec)
288