Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
05ef9cb
Enable coverage options for project in superbuild
reboss Feb 5, 2026
a0968d5
Add an example code coverage work flow
reboss Feb 9, 2026
d14dd57
Add coverage step in CI
reboss Feb 9, 2026
cde4b0a
remove whitespace
reboss Feb 9, 2026
9a710d8
Rename back to projects_to_test (plural)
reboss Mar 6, 2026
b8476b1
fix coverage-test syntax
reboss Mar 6, 2026
eefc01a
Fix keyname
reboss Mar 6, 2026
77b403f
[codecov] fix codecov flow
reboss Apr 2, 2026
90302cc
[hipdnn] remove redundant -fcoverage-mapping from link options
reboss Apr 2, 2026
5ab4b90
add a script to configure coverage jobs
reboss Apr 2, 2026
339f908
integrate therock_configure_coverage.py with coverage workflow
reboss Apr 2, 2026
66f49c3
produce the project name for coverage
reboss Apr 2, 2026
fdc8d8b
configure project separately for code coverage
reboss Apr 2, 2026
e1aa59f
consume project_name in test step as well
reboss Apr 2, 2026
7cf87fe
handle linting
reboss Apr 2, 2026
6f30d38
fix linting
reboss Apr 2, 2026
db77aaa
fix lint
reboss Apr 2, 2026
85f9a6f
fix lint
reboss Apr 2, 2026
28692e1
set enable_coverage to ON
reboss Apr 2, 2026
8734006
Have coverage as a standalone test matrix
reboss Apr 9, 2026
a7f20c8
WIP: Temporarily disable other test matices
reboss Apr 9, 2026
7af9729
rename to coverage_projects for coverage
reboss Apr 14, 2026
a382ebe
bump hashes
reboss Apr 14, 2026
171d34f
Only deploy code cov on gfx942
reboss Apr 14, 2026
87aec54
WIP: just hardcode coverage directory to see if it works
reboss Apr 14, 2026
7562747
Add a mapping to project directories
reboss Apr 14, 2026
f4a5fac
Build any defined project's code coverage flow
reboss Apr 14, 2026
b7a0dce
make sure llvm-cov and llvm-profdata are accessible
reboss Apr 14, 2026
a341cd4
bump hashes
reboss Apr 14, 2026
f85c769
use commit in TheRock that exports llvm-cov and llvm-profdata
reboss Apr 15, 2026
e654e64
use llvm version 22
reboss Apr 15, 2026
67ad414
expose variables needed for code cov
reboss Apr 15, 2026
fb0beac
actually run on a GPU node :/
reboss Apr 16, 2026
8b14ad1
split build and test for coverage
reboss Apr 17, 2026
bd665f4
bump hashes
reboss Apr 20, 2026
93bf741
change dir name
reboss Apr 20, 2026
2de268d
bump container images
reboss Apr 20, 2026
ae67d8b
use proper container for testing
reboss Apr 21, 2026
db484aa
remove redundant pip install
reboss Apr 21, 2026
81e775b
align with therock-ci-linux test flow
reboss Apr 21, 2026
b23ee0b
bump container image
reboss Apr 21, 2026
cf8536b
Add gpu sanity check and bump hashes
reboss Apr 21, 2026
313516a
use correct build dir for coverage
reboss Apr 22, 2026
5f45229
try rebuilding cmake build tree
reboss Apr 23, 2026
6d77203
fetch iree-libs sources in coverage build when IREE is enabled
jainprad Jun 16, 2026
2810829
hipRAND
jainprad Jun 16, 2026
6d1b0f6
hipRANDcmake
jainprad Jun 16, 2026
4c4bf4f
enable hipRAND coverage and fix primary-project selection
jainprad Jun 17, 2026
e579bd4
only override coverage primary with a coverage-enabled changed project
jainprad Jun 17, 2026
f2e323a
pin hipRAND coverage build to RAND-only and fix coverage report tooling
jainprad Jun 17, 2026
7fed235
remove therock-coverage-test job from coverage workflow
jainprad Jun 17, 2026
f16f6a9
run coverage tests via the standard package test flow and add report …
jainprad Jun 17, 2026
9928c18
fix coverage artifact paths for containerized jobs
jainprad Jun 18, 2026
6d9446e
revert hipdnn coverage changes (hipRAND-only PR)
jainprad Jun 18, 2026
39296ee
make coverage report job self-sufficient for llvm tooling
jainprad Jun 18, 2026
a7635d2
use a current TheRock ref for the coverage test stage
jainprad Jun 18, 2026
e0af92a
run coverage report step under bash
jainprad Jun 18, 2026
0bb7b7d
stage llvm tool dependency libraries for the coverage report
jainprad Jun 19, 2026
2b5b026
stage SONAME symlinks for coverage llvm tool dependencies
jainprad Jun 19, 2026
033be35
annotate coverage HTML, upload to Codecov, and emit a paths/links file
jainprad Jun 20, 2026
9874fdf
adopt documented coverage structure (YAML + metadata + coverage_runne…
jainprad Jun 22, 2026
d39dab1
fix Codecov upload (glibc) and surface coverage summary in step log
jainprad Jun 22, 2026
eac40b5
extend coverage artifact retention
jainprad Jun 23, 2026
3fea311
only show the Codecov link in the summary when the upload succeeded
jainprad Jun 24, 2026
b35db84
add rocRAND as an independent coverage component
jainprad Jun 25, 2026
794823f
add rocFFT as an independent coverage component
jainprad Jun 25, 2026
7b84c9a
scope coverage profraw download to the component
jainprad Jun 25, 2026
ee00f99
add rocBLAS and rocSPARSE as independent coverage components
jainprad Jun 28, 2026
d0a6601
format coverage metadata table with black
jainprad Jun 28, 2026
18515e5
format coverage runner and metadata exporter with black
jainprad Jun 28, 2026
1dc6f94
skip coverage report gracefully when no profraw is produced
jainprad Jun 29, 2026
7ddf3f6
drop rocSPARSE coverage component
jainprad Jun 29, 2026
3a35827
exit coverage report step cleanly when no profraw was produced
jainprad Jun 29, 2026
1517bc5
add header-only coverage for rocPRIM, hipCUB, rocThrust
jainprad Jun 29, 2026
260d3f8
scope header-only test binaries to the component's test subproject
jainprad Jun 29, 2026
a039ffa
gate coverage on <PROJECT>_ENABLE_COVERAGE instead of shared vars
jainprad Jun 30, 2026
867a041
move codecov flag and rocThrust SQLite fallback to separate PRs
jainprad Jun 30, 2026
8354102
gate coverage solely on <PROJECT>_ENABLE_COVERAGE
jainprad Jun 30, 2026
07a0328
address coverage review: inline llvm, disable header-only, restore te…
jainprad Jul 8, 2026
65fe4d2
fix(rocrand): make AMD SMI a soft dependency in benchmarks
jainprad Jul 9, 2026
5aa14ed
ci(coverage): qualify Codecov upload for tokenless fork PRs
jainprad Jul 9, 2026
e3b75db
ci(coverage): pass --git-service github for tokenless Codecov upload
jainprad Jul 9, 2026
56fe929
ci(coverage): remove unused coverage_runner.py (review: reboss)
jainprad Jul 10, 2026
d2555b4
ci(coverage): per-project test_categories_coverage.yaml (review: reboss)
jainprad Jul 10, 2026
0bf20db
ci(coverage): drop header-only scaffolding; keep shared-object compon…
jainprad Jul 10, 2026
1517c23
fix(coverage): restore rocPRIM/hipCUB/rocThrust CMakeLists to develop
jainprad Jul 10, 2026
eff5eb6
ci(coverage): address review - gate uploads on success, re-enable CI,…
jainprad Jul 10, 2026
3b5e16c
Revert rocRAND benchmark AMD-SMI soft-dependency change (review: reboss)
jainprad Jul 10, 2026
caade00
ci(coverage): move Codecov upload to the dedicated Codecov PR
jainprad Jul 10, 2026
0a27b3b
Re-apply rocRAND benchmark AMD-SMI soft-dependency (required for cove…
jainprad Jul 13, 2026
6d6728a
ci(coverage): warn+skip (not fail) when a family has no profraw
jainprad Jul 13, 2026
df10506
ci(coverage): generate the coverage report on the test runner
jainprad Jul 13, 2026
2a7bee1
ci(coverage): generate the report from the fetched build, drop covera…
jainprad Jul 13, 2026
20cb807
ci(coverage): drop explanatory comments and reviewer names for finali…
jainprad Jul 13, 2026
1953eba
ci(coverage): address review feedback on the coverage test/report step
jainprad Jul 14, 2026
f634653
ci(coverage): consolidate rocRAND coverage flag and make coverage non…
jainprad Jul 14, 2026
73c3f40
ci(coverage): use the container workspace path for profraw and the re…
jainprad Jul 14, 2026
820b74c
refactor(coverage): standardize rocBLAS/rocFFT coverage flags
jainprad Jul 14, 2026
4f361e8
ci(coverage): surface coverage failures and pin TheRock fork to unblo…
jainprad Jul 14, 2026
a662e34
ci(coverage): declare coverage env vars in env: blocks (reboss review)
jainprad Jul 14, 2026
162be3e
ci(coverage): remove LLVM_PROFILE_FILE from the Test step env (reboss…
jainprad Jul 14, 2026
caf0522
ci(coverage): use aws-linux-scale-rocm-prod runner (geomin12 review)
jainprad Jul 15, 2026
66a0fea
ci(coverage): build therock-artifacts (renamed target) to fix coverag…
jainprad Jul 15, 2026
77ca9d5
ci(coverage): keep coverage non-blocking in CI summary (geomin12 review)
jainprad Jul 15, 2026
f7b9912
ci(coverage): make coverage host-only via -Xarch_host to fix device link
jainprad Jul 15, 2026
31112c8
ci(coverage): make build Report step non-fatal and format-agnostic
jainprad Jul 15, 2026
ac3f31f
ci(coverage): use SHELL: to keep -Xarch_host pairs (fix -fcoverage-ma…
jainprad Jul 15, 2026
302360e
ci(coverage): restore LLVM_PROFILE_FILE so tests emit profraw
jainprad Jul 15, 2026
49ebae2
ci(coverage): TEMP debug - locate profraw files before merge
jainprad Jul 15, 2026
27f223c
ci(coverage): TEMP debug - check .so for __llvm_profile instrumentation
jainprad Jul 15, 2026
1147826
ci(coverage): drop -Xarch_host/SHELL, restore full instrumentation
jainprad Jul 15, 2026
daa5e22
ci(coverage): point coverage build back at ROCm/TheRock@therock_ref
jainprad Jul 16, 2026
ee504eb
ci(coverage): always export LLVM_PROFILE_FILE (comment out coverage_e…
jainprad Jul 16, 2026
1a756e1
Apply suggestion from @reboss
jainprad Jul 16, 2026
8c360e9
ci(coverage): comment out workflow LLVM_PROFILE_FILE export
jainprad Jul 16, 2026
ed3dfd1
ci(coverage): Option B - make PROFILE_DIR a cache var + pass from CI
jainprad Jul 20, 2026
bba65c3
ci(coverage): hipRAND - env-var trigger + build-time instrumentation …
jainprad Jul 20, 2026
ce802a2
ci(coverage): make hipRAND instrumentation self-check definitive
jainprad Jul 20, 2026
8614e95
ci(coverage): fix Prepare step condition (inputs.coverage -> coverage…
jainprad Jul 20, 2026
58ef56f
ci(coverage): harden test-side instrumentation diagnostic
jainprad Jul 20, 2026
4b34011
ci(coverage): run tests via coverage_runner.py (reboss suggestion)
jainprad Jul 20, 2026
31c7663
ci(coverage): scope PR to hipRAND only (remove rocBLAS/rocFFT/rocRAND)
jainprad Jul 20, 2026
a492f98
ci(coverage): restore rocRAND benchmark AMD SMI soft-dependency (fix …
jainprad Jul 20, 2026
c580efe
ci(coverage): fix coverage_runner test-dir derivation (don't die unde…
jainprad Jul 20, 2026
a4d4288
ci(coverage): bust ccache for hipRAND coverage compile (fix 0-symbol …
jainprad Jul 21, 2026
4b3bbc7
Apply suggestion from @reboss
jainprad Jul 21, 2026
b4e158a
ci(coverage): check out ROCm/TheRock@therock_ref (revert reboss/TheRo…
jainprad Jul 21, 2026
5bf6d4b
ci(coverage): re-enable therock-ci-coverage as a gating job in CI sum…
jainprad Jul 21, 2026
abf3462
ci(coverage): fail coverage_runner when no profraw (don't skip silently)
jainprad Jul 21, 2026
9ea1602
Merge branch 'develop' into jainprad/codecoverage_lib_v2
jainprad Jul 22, 2026
184e73f
ci(coverage): swap in instrumented libhiprand for tests (workaround a…
jainprad Jul 22, 2026
74c61bb
ci(coverage): add -path-equivalence so llvm-cov finds sources on the …
jainprad Jul 22, 2026
dd6dfc0
ci(coverage): upload the hipRAND coverage report as a downloadable ar…
jainprad Jul 22, 2026
2189799
ci(coverage): remove dead/unused code from hipRAND coverage flow
jainprad Jul 23, 2026
62bf8d1
Merge branch 'develop' into jainprad/codecoverage_lib_v2
jainprad Jul 27, 2026
8687fa2
Merge branch 'develop' into jainprad/codecoverage_lib_v2
jainprad Jul 28, 2026
6cc4ff4
Merge branch 'develop' into jainprad/codecoverage_lib_v2
jainprad Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions .github/scripts/coverage_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
#!/usr/bin/env python3
"""Run tests with coverage profiling and generate coverage reports.

Invoked by the coverage ``Test`` step in
``.github/workflows/therock-test-component.yml``: it sets ``LLVM_PROFILE_FILE``,
runs the component's tests via ctest to produce profraw files, then merges them
with ``llvm-profdata`` and renders text/HTML/LCOV reports with ``llvm-cov``. It is
driven by the ``coverage_metadata.json`` produced by ``export_coverage_metadata.py``.

Object and llvm tool locations are resolved by name within ``--build-dir`` so the
script works whether it is pointed at a full build/dist tree or a staged artifact.
"""
import argparse
import json
import logging
import os
import subprocess
from pathlib import Path

logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")


def find_tool(build_dir: Path, name: str) -> Path | None:
"""Locate an executable ``name`` inside ``build_dir`` (prefer bin/ dirs)."""
candidates = [p for p in build_dir.rglob(name) if p.is_file()]
if not candidates:
return None
candidates.sort(key=lambda p: (0 if p.parent.name == "bin" else 1, len(str(p))))
return candidates[0]


def resolve_objects(build_dir: Path, metadata: dict) -> list[Path]:
"""Resolve coverage object files (shared libraries) within build_dir."""
objects: list[Path] = []

# Prefer the explicit relative paths recorded at export time, if present.
rel_objects = metadata.get("coverage_objects", {}).get("libraries", []) or []
for rel in rel_objects:
candidate = build_dir / rel
if candidate.is_file():
objects.append(candidate)

# Fall back to resolving by basename (handles a different layout than export).
if not objects:
basenames = metadata.get("object_basenames", {}).get("libraries", []) or []
for basename in basenames:
hits = [p for p in build_dir.rglob(f"{basename}*") if p.is_file()]
# Prefer concrete files (e.g. libhiprand.so.1.1) over bare symlinks,
# and the most specific (longest) name.
hits.sort(key=lambda p: (not p.is_symlink(), len(p.name)), reverse=True)
if hits:
objects.append(hits[0])

# De-duplicate while preserving order.
seen, unique = set(), []
for obj in objects:
key = obj.resolve()
if key not in seen:
seen.add(key)
unique.append(obj)
return unique


def set_coverage_environment(metadata: dict, coverage_dir: Path):
pattern = metadata.get("llvm_profile_pattern", "%m")
profraw_dir = coverage_dir / "profraw"
profraw_dir.mkdir(parents=True, exist_ok=True)
profile_file = str(profraw_dir / f"{pattern}.profraw")
os.environ["LLVM_PROFILE_FILE"] = profile_file
logging.info("Set LLVM_PROFILE_FILE=%s", profile_file)


def run_tests(test_dir: Path, metadata: dict) -> int:
category = metadata.get("test_category", "")
cmd = [
"ctest",
"--test-dir",
str(test_dir),
"--output-on-failure",
"--parallel",
"8",
"--timeout",
"7200",
]
if category:
cmd += ["-L", category]
logging.info("Running tests: %s", " ".join(cmd))
return subprocess.run(cmd).returncode


def merge_profraw_files(llvm_profdata: Path, profraw_dir: Path, out_path: Path) -> Path:
profraw_files = [str(p) for p in profraw_dir.rglob("*.profraw")]
if not profraw_files:
raise RuntimeError(f"No .profraw files found under {profraw_dir}")
logging.info("Merging %d profraw file(s)", len(profraw_files))
subprocess.run(
[str(llvm_profdata), "merge", "-sparse", "-o", str(out_path), *profraw_files],
check=True,
)
logging.info("Created %s", out_path)
return out_path


def generate_reports(
llvm_cov: Path,
llvm_cxxfilt: Path | None,
objects: list[Path],
ignore_regex: str,
profdata: Path,
coverage_dir: Path,
project: str,
path_equivalence: str | None = None,
):
object_args: list[str] = []
for obj in objects:
object_args += ["-object", str(obj)]
ignore_args = [f"-ignore-filename-regex={ignore_regex}"] if ignore_regex else []
# Map the build-node source prefix to the local checkout so llvm-cov can find
# sources for annotation (the build stages rocm-libraries at the workspace root;
# the test node checks it out under <workspace>/rocm-libraries).
patheq_args = [f"-path-equivalence={path_equivalence}"] if path_equivalence else []

text_report = coverage_dir / f"code_cov_{project}.report"
logging.info("Generating text report -> %s", text_report)
with open(text_report, "w") as f:
subprocess.run(
[
str(llvm_cov),
"report",
*object_args,
f"-instr-profile={profdata}",
*ignore_args,
*patheq_args,
],
stdout=f,
check=True,
)
print(text_report.read_text())

logging.info("Generating HTML report -> %s", coverage_dir)
show_cmd = [
str(llvm_cov),
"show",
*object_args,
f"-instr-profile={profdata}",
*ignore_args,
*patheq_args,
"--format=html",
f"--output-dir={coverage_dir}",
]
if llvm_cxxfilt is not None:
show_cmd.insert(2, f"-Xdemangler={llvm_cxxfilt}")
subprocess.run(show_cmd, check=True)

lcov_file = coverage_dir / "coverage.info"
logging.info("Generating LCOV export -> %s", lcov_file)
with open(lcov_file, "w") as f:
subprocess.run(
[
str(llvm_cov),
"export",
*object_args,
f"-instr-profile={profdata}",
*ignore_args,
*patheq_args,
"--format=lcov",
],
stdout=f,
check=True,
)


def main():
parser = argparse.ArgumentParser(description="Run/aggregate coverage and report")
parser.add_argument(
"--build-dir",
type=Path,
required=True,
help="Tree to resolve coverage objects and llvm tools from",
)
parser.add_argument(
"--metadata",
type=Path,
required=True,
help="coverage_metadata.json from export_coverage_metadata.py",
)
parser.add_argument(
"--coverage-dir", type=Path, required=True, help="Output directory for reports"
)
parser.add_argument(
"--test-dir",
type=Path,
default=None,
help="ctest directory (default: --build-dir) when running tests",
)
parser.add_argument(
"--path-equivalence",
type=str,
default=None,
help="Passed to llvm-cov as -path-equivalence=<from>,<to> so it can locate "
"sources when the build-time path differs from the local checkout",
)
args = parser.parse_args()

with open(args.metadata) as f:
metadata = json.load(f)
project = metadata.get("project", "project")
logging.info("Coverage for project: %s", project)

args.coverage_dir.mkdir(parents=True, exist_ok=True)
profraw_dir = args.coverage_dir / "profraw"

# Resolve tooling. Tools link libLLVM and bundled sysdeps that sit next to
# them, so add their directory to LD_LIBRARY_PATH.
llvm_profdata = find_tool(args.build_dir, "llvm-profdata")
llvm_cov = find_tool(args.build_dir, "llvm-cov")
llvm_cxxfilt = find_tool(args.build_dir, "llvm-cxxfilt")
if llvm_profdata is None or llvm_cov is None:
raise FileNotFoundError(
f"llvm-profdata/llvm-cov not found under {args.build_dir}"
)
tool_dirs = {str(t.parent) for t in (llvm_profdata, llvm_cov, llvm_cxxfilt) if t}
os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(
[*tool_dirs, os.environ.get("LD_LIBRARY_PATH", "")]
)
for t in (llvm_profdata, llvm_cov, llvm_cxxfilt):
if t:
t.chmod(0o755)

objects = resolve_objects(args.build_dir, metadata)
if not objects:
raise RuntimeError("No coverage object files could be resolved.")
logging.info("Coverage objects: %s", ", ".join(str(o) for o in objects))

set_coverage_environment(metadata, args.coverage_dir)
rc = run_tests(args.test_dir or args.build_dir, metadata)
if rc != 0:
logging.warning("Tests exited with %d; continuing with coverage.", rc)

# Coverage is a gating job: if the tests produced no profraw, fail loudly
# instead of passing as a silent no-op. An empty result means the library
# under test was not exercised or is not instrumented (e.g. the shipped
# artifact lacks instrumentation), which must surface rather than be hidden.
if not list(profraw_dir.rglob("*.profraw")):
logging.error(
"No .profraw files found under %s; the tests produced no coverage "
"data (the library under test is likely not instrumented). "
"Failing the coverage job.",
profraw_dir,
)
raise SystemExit(1)

profdata = merge_profraw_files(
llvm_profdata, profraw_dir, args.coverage_dir / f"{project}.profdata"
)
generate_reports(
llvm_cov,
llvm_cxxfilt,
objects,
metadata.get("ignore_filename_regex", ""),
profdata,
args.coverage_dir,
project,
path_equivalence=args.path_equivalence,
)
logging.info("Coverage generation complete.")


if __name__ == "__main__":
main()
127 changes: 127 additions & 0 deletions .github/scripts/export_coverage_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
"""Export coverage metadata from a build tree to JSON for use in the report job.

This is the build-time half of the coverage flow described in TheRock's coverage
design docs. It reads ``test_categories_coverage.yaml``, verifies the configured
coverage objects exist in the build/dist tree, and writes a ``coverage_metadata.json``
that the coverage report job consumes later to merge profraw files and produce a report.

Object/tool names are recorded by file name (basename). The report job locates the
actual files in whatever layout it has (build dist or staged artifact), so version
suffixes such as ``libhiprand.so.1.1`` are handled by the runner.
"""
import argparse
import json
import logging
from pathlib import Path

import yaml

logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")


def load_coverage_config(config_path: Path) -> dict:
with open(config_path) as f:
return yaml.safe_load(f)


def find_by_basename(build_dir: Path, basename: str) -> list[str]:
"""Find files in ``build_dir`` whose name starts with ``basename``.

Matches versioned shared libraries (e.g. libhiprand.so -> libhiprand.so.1.1).
Returns paths relative to ``build_dir`` so the metadata is location independent.
"""
matches: list[str] = []
for path in build_dir.rglob(f"{basename}*"):
if path.is_file():
matches.append(str(path.relative_to(build_dir)))
return sorted(set(matches))


def export_metadata(
build_dir: Path,
project: str,
config_path: Path,
output_path: Path,
):
config = load_coverage_config(config_path)
# The coverage config is a per-project file: the document is the project's
# config directly, kept next to the project's test_categories.yaml.
key = project.lower()
project_config = config or {}

if not project_config.get("enabled", False):
logging.info("Coverage disabled for %s; nothing to export.", key)
return

objects = project_config.get("coverage_objects", {})

# Shared libraries are located by basename and staged separately (by the
# workflow) from dist/lib; the runner re-resolves them by basename.
found = {"libraries": []}
for basename in objects.get("libraries", []) or []:
hits = find_by_basename(build_dir, basename)
if hits:
found["libraries"].extend(hits)
else:
logging.warning("Coverage object not found for libraries: %s", basename)

metadata = {
"project": key,
"coverage_objects": found,
# Basenames are kept so the runner can re-resolve in a different layout.
"object_basenames": {
"libraries": objects.get("libraries", []) or [],
},
"ignore_filename_regex": project_config.get("ignore_filename_regex", ""),
"llvm_profile_pattern": project_config.get("llvm_profile_pattern", "%m"),
"test_category": project_config.get("test_category", ""),
"llvm_tools": {
"llvm_profdata": "llvm-profdata",
"llvm_cov": "llvm-cov",
"llvm_cxxfilt": "llvm-cxxfilt",
},
}

output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, "w") as f:
json.dump(metadata, f, indent=2)

logging.info("Exported coverage metadata to %s", output_path)
logging.info(" Libraries found: %d", len(found["libraries"]))


def main():
parser = argparse.ArgumentParser(description="Export coverage metadata to JSON")
parser.add_argument(
"--build-dir",
type=Path,
required=True,
help="Build/dist tree to search for coverage objects",
)
parser.add_argument(
"--project",
type=str,
required=True,
help="Project key or name (e.g. hiprand / HIPRAND)",
)
parser.add_argument(
"--config",
type=Path,
required=True,
help="Path to test_categories_coverage.yaml",
)
parser.add_argument(
"--output", type=Path, required=True, help="Output coverage_metadata.json path"
)
args = parser.parse_args()
export_metadata(
args.build_dir,
args.project,
args.config,
args.output,
)


if __name__ == "__main__":
main()
Loading
Loading