| # Generating and viewing Tint code-coverage |
| |
| Requirements: |
| |
| * Host running Linux or macOS |
| * [vpython3](https://chromium.googlesource.com/chromium/tools/depot_tools/+/HEAD/vpython3) |
| (usually provided by `depot_tools`) |
| * Clang toolchain |
| |
| ## Building Tint with coverage generation enabled |
| |
| To generate coverage, you must build with Clang source-based coverage |
| instrumentation enabled. |
| |
| ### Using GN (Recommended) |
| |
| Add the following flags to your `args.gn`: |
| |
| ```gn |
| use_clang_coverage = true |
| is_component_build = false |
| is_debug = false |
| dcheck_always_on = true |
| ``` |
| |
| If you are building a fuzzer target, also include: |
| |
| ```gn |
| optimize_for_fuzzing = false |
| use_clang_modules = false |
| use_libfuzzer = true |
| ``` |
| |
| ### Using CMake |
| |
| Add the additional `-DDAWN_EMIT_COVERAGE=1` CMake flag. |
| |
| To use the `coverage.py` script's automated building features, you |
| must use the Ninja generator: |
| |
| ```bash |
| cmake -G Ninja -DDAWN_EMIT_COVERAGE=1 .. |
| ``` |
| |
| If you use a different generator (like Make), you must build your |
| targets manually and use the `--no-compile` flag with the script. |
| |
| ## Generating Coverage Reports |
| |
| Use the `tools/code_coverage/coverage.py` script to run your targets |
| and generate reports. (This is the Chromium maintained script that |
| replaces the previous Tint only script, |
| `tools/tint-generate-coverage`). |
| |
| ### 1. Generate LCOV for VSCode |
| |
| To use the [VSCode Coverage |
| Gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) |
| extension, generate an LCOV tracefile: |
| |
| ```bash |
| vpython3 tools/code_coverage/coverage.py tint_unittests \ |
| -b out/gn-coverage \ |
| -o coverage_report \ |
| --format lcov \ |
| -c 'out/gn-coverage/tint_unittests' |
| ``` |
| |
| |
| The resulting file will be located at |
| `coverage_report/linux/coverage.lcov`. |
| |
| ### 2. Generate an HTML Report |
| |
| To generate a browsable HTML report with line-by-line coverage: |
| |
| ```bash |
| vpython3 tools/code_coverage/coverage.py tint_unittests \ |
| --no-component-view \ |
| -b out/gn-coverage \ |
| -o coverage_report \ |
| --format html \ |
| -c 'out/gn-coverage/tint_unittests' |
| ``` |
| |
| Open `coverage_report/linux/index.html` in your browser. |
| |
| ### 3. Advanced: Fuzzers with Dynamic Objects (Mesa/Vulkan) |
| |
| If you are running a fuzzer that dynamically loads a Vulkan driver |
| (like Mesa's `lvp`), you need to explicitly include the driver object |
| and map its source paths: |
| |
| ```bash |
| vpython3 tools/code_coverage/coverage.py tint_ir_fuzzer \ |
| --no-component-view \ |
| -b out/gn-coverage \ |
| -o coverage_report \ |
| --format html \ |
| -a out/gn-coverage/gen/third_party/mesa/install/lib/x86_64-linux-gnu/libvulkan_lvp.so \ |
| --path-equivalence=/third_party/mesa,$(pwd)/third_party/mesa \ |
| --path-equivalence=$(pwd)/out/gn-coverage/src,$(pwd)/out/gn-coverage/gen/third_party/mesa/mesa_setup/src \ |
| -i '\/usr\/.*' \ |
| -c 'out/gn-coverage/tint_ir_fuzzer -max_total_time=30 --vk_icd=./out/gn-coverage/gen/third_party/mesa/install/share/vulkan/icd.d/lvp_icd.x86_64.json' |
| ``` |
| |
| * `-a`: Adds the dynamically loaded driver as object source to the |
| coverage calculation. |
| * `--path-equivalence`: Maps paths recorded in the binary (which may |
| be absolute or relative to build artifacts) to your local |
| checkout. |
| * Multiple `--path-equivalence` flags can be provided to handle |
| different source roots (e.g., standard sources vs. generated |
| files). |
| * `-i '\/usr\/.*` is used to not include system files that are |
| outside the source tree. |
| |
| ## Troubleshooting |
| |
| ### 403 error when generating HTML reports |
| If you see something like this: |
| ``` |
| [2026-04-13 13:20:20,757 INFO] Generating code coverage report in html (this can take a while depending on size of target!). |
| Traceback (most recent call last): |
| File "/home/<user>/workspace/dawn/tools/code_coverage/coverage.py", line 1271, in <module> |
| sys.exit(Main()) |
| ^^^^^^ |
| File "/home/<user>/workspace/dawn/tools/code_coverage/coverage.py", line 1266, in Main |
| _GenerateCoverageReport(args, binary_paths, profdata_file_path, |
| File "/home/<user>/workspace/dawn/tools/code_coverage/coverage.py", line 968, in _GenerateCoverageReport |
| component_mappings = json.load(urlopen(COMPONENT_MAPPING_URL)) |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 216, in urlopen |
| return opener.open(url, data, timeout) |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 525, in open |
| response = meth(req, response) |
| ^^^^^^^^^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 634, in http_response |
| response = self.parent.error( |
| ^^^^^^^^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 563, in error |
| return self._call_chain(*args) |
| ^^^^^^^^^^^^^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 496, in _call_chain |
| result = func(*args) |
| ^^^^^^^^^^^ |
| File "/home/<user>/.cache/vpython-root.119166/store/cpython+l5fnajrvijf7cvdkjqmbicg3i8/contents/lib/python3.11/urllib/request.py", line 643, in http_error_default |
| raise HTTPError(req.full_url, code, msg, hdrs, fp) |
| urllib.error.HTTPError: HTTP Error 403: Forbidden |
| |
| ``` |
| |
| then the likely cause is missing `--no-component-view` from the flags. |
| |
| The component view functionality depends on the mapping of directories |
| in a Chromium checkout to components in the issue tracker, so |
| misbehaves when run in a Dawn checkout. Fixing this would add |
| complexity upstream for a view that doesn't provide any useful |
| information in the report, since it would just tell you all of the |
| code in the Dawn repo belongs to either the Dawn or Tint component. |