Files
filament/docs/notes/coverage.html
2025-09-18 14:40:07 -07:00

296 lines
14 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Code coverage analysis - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="generating-backend-code-coverage"><a class="header" href="#generating-backend-code-coverage">Generating Backend Code Coverage</a></h1>
<p>Code coverage analysis helps visualize which parts of the backend are exercised by backend tests.
This guide outlines the process for generating an HTML coverage report for Filament's backend on
macOS.</p>
<h2 id="1-prerequisites-install-clang-and-llvm-tools"><a class="header" href="#1-prerequisites-install-clang-and-llvm-tools">1. Prerequisites: Install Clang and LLVM tools</a></h2>
<p>You'll need a recent version of <strong>Clang</strong> and its corresponding <strong>LLVM tools</strong> for code coverage.
You can install these using Homebrew or MacPorts.</p>
<h3 id="using-homebrew"><a class="header" href="#using-homebrew">Using Homebrew</a></h3>
<p>Install the <code>llvm</code> package:</p>
<pre><code class="language-bash">brew install llvm
</code></pre>
<p>This typically installs the tools in a location like <code>/usr/local/opt/llvm/bin</code>. You may need to add
this to your <code>PATH</code> environment variable.</p>
<h3 id="using-macports"><a class="header" href="#using-macports">Using MacPorts</a></h3>
<p>Install a specific version of Clang (e.g., version 18):</p>
<pre><code class="language-bash">sudo port install clang-18
</code></pre>
<p>MacPorts often adds version suffixes to the tool names (e.g., <code>llvm-cov-mp-18</code>).</p>
<h3 id="required-tools"><a class="header" href="#required-tools">Required Tools</a></h3>
<p>Ensure you can locate the following tools from your installation:</p>
<ul>
<li><code>clang</code> and <code>clang++</code> (The C/C++ compilers)</li>
<li><code>llvm-profdata</code> (For merging coverage data)</li>
<li><code>llvm-cov</code> (For generating reports)</li>
</ul>
<p>The rest of this guide assumes your tools are in your <code>PATH</code>. If not, you'll need to use the full
path to each executable.</p>
<h2 id="2-build-filament-with-coverage-enabled"><a class="header" href="#2-build-filament-with-coverage-enabled">2. Build Filament with Coverage Enabled</a></h2>
<p>Compile the <code>backend_test_mac</code> target with coverage instrumentation. This is done by setting the
<code>CC</code> and <code>CXX</code> environment variables to point to your Clang compiler and using the <code>-V</code> flag in the
build script.</p>
<pre><code class="language-bash">CC=clang CXX=clang++ ./build.sh -V -p desktop debug backend_test_mac
</code></pre>
<p><em>If your Clang executables aren't in your <code>PATH</code> or have version suffixes, provide the full name or
path (e.g., <code>CC=/opt/local/bin/clang CXX=/opt/local/bin/clang++</code>).</em></p>
<h2 id="3-run-the-backend-tests"><a class="header" href="#3-run-the-backend-tests">3. Run the Backend Tests</a></h2>
<p>Running the test suite will generate the raw coverage data needed for the report.</p>
<ol>
<li>
<p>Navigate to the build output directory:</p>
<pre><code class="language-bash">cd out/cmake-debug/filament/backend
</code></pre>
</li>
<li>
<p>Run the tests for a specific backend (e.g., Metal):</p>
<pre><code class="language-bash">./backend_test_mac --api metal
</code></pre>
</li>
</ol>
<p>This command creates a <code>default.profraw</code> file in the current directory, which contains the raw
execution profile data.</p>
<h2 id="4-generate-the-coverage-report"><a class="header" href="#4-generate-the-coverage-report">4. Generate the Coverage Report</a></h2>
<p>Finally, process the raw data and generate an HTML report.</p>
<ol>
<li>
<p><strong>Merge the raw profile data</strong> into a single file using <code>llvm-profdata</code>.</p>
<pre><code class="language-bash">llvm-profdata merge -sparse default.profraw -o filament.profdata
</code></pre>
<p><em>Remember to use the version-specific tool name if required (e.g., <code>llvm-profdata-mp-18</code>).</em></p>
</li>
<li>
<p><strong>Generate the HTML report</strong> using <code>llvm-cov</code>. This command creates a report for the entire
<code>backend_test_mac</code> executable.</p>
<pre><code class="language-bash">llvm-cov show ./backend_test_mac \
-instr-profile=filament.profdata \
-format=html \
-show-line-counts-or-regions &gt; coverage.html
</code></pre>
<p><em>To view coverage for a <strong>specific source file</strong>, add its path at the end of the command:</em></p>
<pre><code class="language-bash">llvm-cov show ./backend_test_mac \
-instr-profile=filament.profdata \
-format=html \
-show-line-counts-or-regions \
-- ../../../../filament/backend/src/metal/MetalDriver.mm &gt; coverage.html
</code></pre>
</li>
<li>
<p><strong>Open the report</strong> in your browser:</p>
<pre><code class="language-bash">open coverage.html
</code></pre>
</li>
</ol>
<p>In the report, code paths that were not executed during the test run will be highlighted in red.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/instruments.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/instruments.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/performance_analysis.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>