[libcxx-commits] [libcxx] [libc++] Include some Lit features in LNT submissions (PR #218043)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Sep 16 09:58:14 PDT 2026
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/218043
>From 61cd2739017ad5b554c01a7d866b0b990b2c72e2 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Fri, 21 Aug 2026 17:27:06 -0400
Subject: [PATCH] [libc++] Include some Lit features in LNT submissions
The Lit test suite already sniffs out some properties of the library
configuration we are testing / benchmarking. This patch augments the
run-benchmarks script to pick up a few of these detected features so
they can be included in the Machine information contained in submissions.
This is important to help pin down exactly what is being benchmarked.
---
libcxx/utils/ci/lnt/run-benchmarks | 64 +++++++++++++++++++++++++-----
libcxx/utils/test-at-commit | 12 +++++-
2 files changed, 64 insertions(+), 12 deletions(-)
diff --git a/libcxx/utils/ci/lnt/run-benchmarks b/libcxx/utils/ci/lnt/run-benchmarks
index 9d9c63ca4ba37..e76debafa8d75 100755
--- a/libcxx/utils/ci/lnt/run-benchmarks
+++ b/libcxx/utils/ci/lnt/run-benchmarks
@@ -14,6 +14,7 @@ import logging
import os
import pathlib
import platform
+import re
import shutil
import subprocess
import sys
@@ -46,6 +47,43 @@ def gather_machine_information(args):
return info
+def gather_lit_features(lit, lit_params, tests):
+ """
+ Gather the Lit features in effect for the configuration we benchmarked, as a dictionary of
+ feature name to feature value.
+ """
+ # Lit features that we report as part of the machine information, and the names
+ # we use in that machine information.
+ REPORTED_FEATURES = {
+ 'libcpp-abi-version': 'abi_version',
+ 'libcpp-hardening-mode': 'hardening_mode',
+ }
+
+ if not lit.is_file():
+ logging.warning(f'{lit} does not exist: not reporting any Lit feature')
+ return {}
+
+ # Lit prints the features of the configuration it discovered and exits without running anything.
+ command = [str(c) for c in [lit, '--show-suites', *lit_params, tests]]
+ logging.debug(f'$ {" ".join(command)}')
+ try:
+ output = subprocess.check_output(command, stderr=subprocess.PIPE).decode()
+ except subprocess.CalledProcessError as e:
+ logging.warning(f'Could not determine the Lit features in effect: {e.stderr.decode()}')
+ return {}
+
+ matches = re.findall(r'^\s*Available Features:\s*(.+)$', output, flags=re.MULTILINE)
+ if len(matches) != 1:
+ logging.warning(f'Expected exactly one list of features in the output of Lit, got {len(matches)}')
+ return {}
+ parsed = dict(f.split('=', 1) for f in matches[0].split() if '=' in f)
+
+ reported = {}
+ for (name, value) in parsed.items():
+ if name in REPORTED_FEATURES:
+ reported[REPORTED_FEATURES[name]] = value
+ return reported
+
def gather_run_information(args):
"""
Gather the run information to upload to LNT as part of the submission.
@@ -160,25 +198,28 @@ def main(argv):
run(build_cmd, enforce_success=False) # if the build fails, carry on: we'll fail later and submit empty LNT results
logging.info(f'Running benchmarks from {args.test_suite_commit} against libc++ {args.benchmark_commit}')
+ lit_params = ['--param', f'compiler={args.compiler}',
+ '--param', 'optimization=speed',
+ '--param', 'std=c++26',
+ '--param', 'enable_werror=False'] # older versions of the library trigger new warnings, don't fail
+ if args.spec_dir is not None:
+ lit_params += ['--param', f'spec_dir={args.spec_dir}']
cmd = [args.git_repo / 'libcxx/utils/test-at-commit',
'--git-repo', args.git_repo,
- '--build-dir', artifacts / 'benchmarks',
+ '--build-dir', artifacts / 'benchmarks-build',
'--test-suite-commit', args.test_suite_commit,
+ '--tmp-src-dir', artifacts / 'benchmarks-src',
'--libcxx-installation', artifacts / 'libcxx-install',
'--compiler', args.compiler,
'--',
'-j1', '--time-tests', '--test-output=failed',
- '--param', f'compiler={args.compiler}',
- '--param', 'optimization=speed',
- '--param', 'std=c++26',
- '--param', 'enable_werror=False', # older versions of the library trigger new warnings, don't fail
- artifacts / 'benchmarks/libcxx/test/benchmarks']
- if args.spec_dir is not None:
- cmd += ['--param', f'spec_dir={args.spec_dir}']
+ *lit_params,
+ artifacts / 'benchmarks-build/libcxx/test/benchmarks']
if args.filter is not None:
cmd += ['--filter', args.filter]
run(cmd, enforce_success=False) # some benchmarks may fail to build/run at some commits, and that's okay
- consolidate = [args.git_repo / 'libcxx/utils/consolidate-benchmarks', artifacts / 'benchmarks']
+
+ consolidate = [args.git_repo / 'libcxx/utils/consolidate-benchmarks', artifacts / 'benchmarks-build']
if args.dry_run:
run(consolidate)
else:
@@ -190,7 +231,10 @@ def main(argv):
importreport = ['lnt', 'importreport', '--order', str(order), '--machine', args.machine]
for arg in dict_to_params(gather_run_information(args)):
importreport += ['--run-info', arg]
- for arg in dict_to_params(gather_machine_information(args)):
+ machine_info = {**gather_machine_information(args),
+ **gather_lit_features(artifacts / 'benchmarks-build/bin/llvm-lit', lit_params,
+ artifacts / 'benchmarks-build/libcxx/test/benchmarks')}
+ for arg in dict_to_params(machine_info):
importreport += ['--machine-info', arg]
output = args.output.resolve()
importreport += [artifacts / 'benchmarks.lnt', output]
diff --git a/libcxx/utils/test-at-commit b/libcxx/utils/test-at-commit
index b02c571ca9b1b..83e1e570d3238 100755
--- a/libcxx/utils/test-at-commit
+++ b/libcxx/utils/test-at-commit
@@ -96,6 +96,11 @@ def main(argv):
'separated from other arguments with a `--`.')
parser.add_argument('--git-repo', type=directory_path, default=pathlib.Path(os.getcwd()),
help='Optional path to the Git repository to use. By default, the current working directory is used.')
+ parser.add_argument('--tmp-src-dir', type=pathlib.Path, required=False,
+ help='Optional path to use for the ephemeral checkout of the test suite. By default, a temporary '
+ 'directory is used and it is cleaned up after the run. If a custom directory is specified, it '
+ 'is not cleaned up automatically. Note that the build directory refers to that checkout, so '
+ 'keeping it around is required in order to use the build directory after the run.')
args = parser.parse_args(argv)
args.build_dir = args.build_dir.resolve()
@@ -115,8 +120,11 @@ def main(argv):
if args.test_suite_commit is None:
test_suite_sources = args.git_repo
else:
- tempdirs.append(tempfile.TemporaryDirectory())
- test_suite_sources = pathlib.Path(tempdirs[-1].name)
+ if args.tmp_src_dir is not None:
+ test_suite_sources = args.tmp_src_dir
+ else:
+ tempdirs.append(tempfile.TemporaryDirectory())
+ test_suite_sources = pathlib.Path(tempdirs[-1].name)
checkout_dirs = [d for d in LIBCXX_REQUIRED_DIRECTORIES if exists_in_commit(args.git_repo, args.test_suite_commit, d)]
checkout_subdirectories(args.git_repo, args.test_suite_commit, checkout_dirs, test_suite_sources)
More information about the libcxx-commits
mailing list