Requirements:
depot_tools)To generate coverage, you must build with Clang source-based coverage instrumentation enabled.
Add the following flags to your args.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:
optimize_for_fuzzing = false use_clang_modules = false use_libfuzzer = true
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:
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.
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).
To use the VSCode Coverage Gutters extension, generate an LCOV tracefile:
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.
To generate a browsable HTML report with line-by-line coverage:
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.
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:
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.--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.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.