Skip to content

gh-112536: Add --tsan test for reasonable TSAN execution times. #116601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 15, 2024
7 changes: 7 additions & 0 deletions Doc/library/test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,13 @@ The :mod:`test.support` module defines the following constants:
Set to the ``data`` directory within the test package.


.. data:: TSAN

Set when tests can be skipped when they are not useful for ThreadSanitizer.

.. versionadded:: 3.13


.. data:: MAX_Py_ssize_t

Set to :data:`sys.maxsize` for big memory tests.
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/libregrtest/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ def __init__(self, **kwargs) -> None:
self.match_tests: TestFilter = []
self.pgo = False
self.pgo_extended = False
self.tsan = False
self.worker_json = None
self.start = None
self.timeout = None
Expand Down Expand Up @@ -333,6 +334,8 @@ def _create_parser():
help='enable Profile Guided Optimization (PGO) training')
group.add_argument('--pgo-extended', action='store_true',
help='enable extended PGO training (slower training)')
group.add_argument('--tsan', dest='tsan', action='store_true',
help='enable TSAN test')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain what "TSAN test" means here? From the rest of the diff it sounds like it's "Tests that pass in a reasonable amount of time with TSAN enabled", but that's not clear from this help string.

group.add_argument('--fail-env-changed', action='store_true',
help='if a test file alters the environment, mark '
'the test as failed')
Expand Down
11 changes: 10 additions & 1 deletion Lib/test/libregrtest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from .runtests import RunTests, HuntRefleak
from .setup import setup_process, setup_test_dir
from .single import run_single_test, PROGRESS_MIN_TIME
from .tsan import setup_tsan_tests
from .utils import (
StrPath, StrJSON, TestName, TestList, TestTuple, TestFilter,
strip_py_suffix, count, format_duration,
Expand Down Expand Up @@ -56,6 +57,7 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):
self.quiet: bool = ns.quiet
self.pgo: bool = ns.pgo
self.pgo_extended: bool = ns.pgo_extended
self.tsan: bool = ns.tsan

# Test results
self.results: TestResults = TestResults()
Expand Down Expand Up @@ -87,7 +89,11 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = False):

# Workers
if ns.use_mp is None:
num_workers = 0 # run sequentially
if ns.tsan:
# For TSAN tests, use number of CPU of the current process.
num_workers = os.process_cpu_count()
else:
num_workers = 0 # run sequentially
elif ns.use_mp <= 0:
num_workers = -1 # use the number of CPUs
else:
Expand Down Expand Up @@ -183,6 +189,9 @@ def find_tests(self, tests: TestList | None = None) -> tuple[TestTuple, TestList
# add default PGO tests if no tests are specified
setup_pgo_tests(self.cmdline_args, self.pgo_extended)

if self.tsan:
setup_tsan_tests(self.cmdline_args)

exclude_tests = set()
if self.exclude:
for arg in self.cmdline_args:
Expand Down
43 changes: 43 additions & 0 deletions Lib/test/libregrtest/tsan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Set of tests run by default if --tsan is specified. The tests below were
# chosen to run a thread sanitizer in a reasonable executable time.

TSAN_TESTS = [
'test_asyncio',
'test_capi',
'test_code',
'test_compileall',
'test_concurrent_futures',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

==14799==ThreadSanitizer: starting new threads after multi-threaded fork is not supported. Dying (set die_after_fork=0 to override)

'test_enum',
'test_fork1',
'test_functools',
'test_httpservers',
'test_imaplib',
'test_import',
'test_importlib',
'test_io',
'test_logging',
'test_multiprocessing_forkserver',
'test_multiprocessing_spawn',
'test_pickle',
'test_queue',
'test_list',
'test_dict',
'test_set',
'test_tuple',
'test_smtpnet',
'test_socketserver',
'test_ssl',
'test_syslog',
'test_thread',
'test_threadedtempfile',
'test_threading',
'test_threading_local',
'test_threadsignals',
'test_urllib2net',
'test_weakref'
]


def setup_tsan_tests(cmdline_args):
if not cmdline_args:
cmdline_args[:] = TSAN_TESTS[:]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add --tsan to test.regrtest for running TSAN tests in reasonable execution
times. Patch by Donghee Na.
3 changes: 3 additions & 0 deletions Tools/tsan/supressions.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## reference: https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am going to update the list of supressions.txt when working on the CI things.

race:get_allocator_unlocked
race:set_allocator_unlocked