| ... |
... |
@@ -23,7 +23,7 @@ import subprocess |
|
23
|
23
|
|
|
24
|
24
|
from testglobals import config, ghc_env, default_testopts, brokens, t, \
|
|
25
|
25
|
TestRun, TestResult, TestOptions, PerfMetric
|
|
26
|
|
-from testutil import strip_quotes, lndir, link_or_copy_file, passed, \
|
|
|
26
|
+from testutil import discover_io_managers, strip_quotes, lndir, link_or_copy_file, passed, \
|
|
27
|
27
|
failBecause, residency_testing_metrics, \
|
|
28
|
28
|
stable_perf_counters, \
|
|
29
|
29
|
PassFail, badResult, str_warn, str_removeprefix
|
| ... |
... |
@@ -569,6 +569,34 @@ def extra_ways( ways: List[WayName] ): |
|
569
|
569
|
|
|
570
|
570
|
return helper
|
|
571
|
571
|
|
|
|
572
|
+# -----
|
|
|
573
|
+
|
|
|
574
|
+def _io_managers( name: TestName, opts, io_mgrs: List[str] ) -> None:
|
|
|
575
|
+ opts.io_managers = io_mgrs
|
|
|
576
|
+
|
|
|
577
|
+def io_managers( io_mgrs: List[str] ):
|
|
|
578
|
+ """
|
|
|
579
|
+ Further split test cases into the given IO Managers if available.
|
|
|
580
|
+ Available IO Managers are determined by the test case's way (threaded/non-threads) and OS.
|
|
|
581
|
+ You'll likely want to use `extra_ways(['threaded2'])` if you want to test threaded IO Managers (e.g. mio).
|
|
|
582
|
+ """
|
|
|
583
|
+ return lambda name, opts: _io_managers(name, opts, io_mgrs)
|
|
|
584
|
+
|
|
|
585
|
+def all_available_io_managers( name: TestName, opts ):
|
|
|
586
|
+ """
|
|
|
587
|
+ Further split test cases into all available IO Managers.
|
|
|
588
|
+ Available IO Managers are determined by the test case's way (threaded/non-threads) and OS.
|
|
|
589
|
+ You'll likely want to use `extra_ways(['threaded2'])` to ensure threaded IO Managers are tested (e.g. mio).
|
|
|
590
|
+ """
|
|
|
591
|
+ _io_managers(name, opts, config.io_managers_all)
|
|
|
592
|
+
|
|
|
593
|
+def all_available_io_managers_except(exclude: List[str]):
|
|
|
594
|
+ """
|
|
|
595
|
+ Further split test cases into all available (except the given excluded) IO Managers.
|
|
|
596
|
+ Available IO Managers are determined by the test case's way (threaded/non-threads) and OS.
|
|
|
597
|
+ You'll likely want to use `extra_ways(['threaded2'])` to ensure threaded IO Managers are tested (e.g. mio).
|
|
|
598
|
+ """
|
|
|
599
|
+ return lambda name, opts: _io_managers(name, opts, list(set(config.io_managers_all) - set(exclude)))
|
|
572
|
600
|
|
|
573
|
601
|
# -----
|
|
574
|
602
|
|
| ... |
... |
@@ -1571,6 +1599,15 @@ do_not_copy = ('.hi', '.o', '.dyn_hi' |
|
1571
|
1599
|
, '.dyn_o', '.out'
|
|
1572
|
1600
|
,'.hi-boot', '.o-boot') # 12112
|
|
1573
|
1601
|
|
|
|
1602
|
+def way_supports_io_manager(way: WayName, io_manager: Optional[str]) -> bool:
|
|
|
1603
|
+ # All ways support a default IO Manager
|
|
|
1604
|
+ if io_manager is None:
|
|
|
1605
|
+ return True
|
|
|
1606
|
+
|
|
|
1607
|
+ way_is_threaded = '-threaded' in config.way_flags[way]
|
|
|
1608
|
+ available_io_managers = config.io_managers_threaded if way_is_threaded else config.io_managers_nonthreaded
|
|
|
1609
|
+ return io_manager in available_io_managers
|
|
|
1610
|
+
|
|
1574
|
1611
|
async def test_common_work(name: TestName, opts,
|
|
1575
|
1612
|
func, args) -> None:
|
|
1576
|
1613
|
try:
|
| ... |
... |
@@ -1619,7 +1656,22 @@ async def test_common_work(name: TestName, opts, |
|
1619
|
1656
|
# A test itself can request extra ways by setting opts.extra_ways
|
|
1620
|
1657
|
all_ways = list(OrderedDict.fromkeys(all_ways + [way for way in opts.extra_ways if way not in all_ways]))
|
|
1621
|
1658
|
|
|
1622
|
|
- t.total_test_cases += len(all_ways)
|
|
|
1659
|
+ # We split each way over available io managers
|
|
|
1660
|
+ if len(opts.io_managers) == 0:
|
|
|
1661
|
+ framework_fail(name, None, 'opts.io_managers is empty')
|
|
|
1662
|
+ all_ways_and_io_managers = dict(
|
|
|
1663
|
+ (
|
|
|
1664
|
+ way,
|
|
|
1665
|
+ [io_manager
|
|
|
1666
|
+ for io_manager in opts.io_managers
|
|
|
1667
|
+ if way_supports_io_manager(way, io_manager)
|
|
|
1668
|
+ ]
|
|
|
1669
|
+ )
|
|
|
1670
|
+ for way in all_ways
|
|
|
1671
|
+ )
|
|
|
1672
|
+
|
|
|
1673
|
+ for io_managers in all_ways_and_io_managers.values():
|
|
|
1674
|
+ t.total_test_cases += len(io_managers)
|
|
1623
|
1675
|
|
|
1624
|
1676
|
only_ways = getTestOpts().only_ways
|
|
1625
|
1677
|
ok_way = lambda way: \
|
| ... |
... |
@@ -1702,17 +1754,26 @@ async def test_common_work(name: TestName, opts, |
|
1702
|
1754
|
|
|
1703
|
1755
|
# Run the required tests...
|
|
1704
|
1756
|
for way in do_ways:
|
|
1705
|
|
- if stopping():
|
|
1706
|
|
- break
|
|
1707
|
|
- try:
|
|
1708
|
|
- await do_test(name, way, func, args, files)
|
|
1709
|
|
- except KeyboardInterrupt:
|
|
1710
|
|
- stopNow()
|
|
1711
|
|
- except Exception as e:
|
|
1712
|
|
- traceback.print_exc()
|
|
1713
|
|
- framework_fail(name, way, traceback.format_exc())
|
|
|
1757
|
+ for io_manager in all_ways_and_io_managers[way]:
|
|
|
1758
|
+ if stopping():
|
|
|
1759
|
+ break
|
|
|
1760
|
+ try:
|
|
|
1761
|
+ await do_test(
|
|
|
1762
|
+ name,
|
|
|
1763
|
+ way,
|
|
|
1764
|
+ io_manager,
|
|
|
1765
|
+ func,
|
|
|
1766
|
+ args,
|
|
|
1767
|
+ files)
|
|
|
1768
|
+ except KeyboardInterrupt:
|
|
|
1769
|
+ stopNow()
|
|
|
1770
|
+ except Exception as e:
|
|
|
1771
|
+ traceback.print_exc()
|
|
|
1772
|
+ framework_fail(name, way, traceback.format_exc())
|
|
|
1773
|
+
|
|
|
1774
|
+ for skipped_way in set(all_ways) - set(do_ways):
|
|
|
1775
|
+ t.n_tests_skipped += len(all_ways_and_io_managers[skipped_way])
|
|
1714
|
1776
|
|
|
1715
|
|
- t.n_tests_skipped += len(set(all_ways) - set(do_ways))
|
|
1716
|
1777
|
if getTestOpts().expect == 'missing-lib': t.n_missing_libs += 1
|
|
1717
|
1778
|
|
|
1718
|
1779
|
if config.cleanup and do_ways:
|
| ... |
... |
@@ -1731,6 +1792,7 @@ async def test_common_work(name: TestName, opts, |
|
1731
|
1792
|
|
|
1732
|
1793
|
async def do_test(name: TestName,
|
|
1733
|
1794
|
way: WayName,
|
|
|
1795
|
+ io_manager: Optional[str],
|
|
1734
|
1796
|
func: Callable[..., Awaitable[PassFail]],
|
|
1735
|
1797
|
args,
|
|
1736
|
1798
|
files: Set[str]
|
| ... |
... |
@@ -1738,6 +1800,8 @@ async def do_test(name: TestName, |
|
1738
|
1800
|
opts = getTestOpts()
|
|
1739
|
1801
|
|
|
1740
|
1802
|
full_name = name + '(' + way + ')'
|
|
|
1803
|
+ if io_manager is not None:
|
|
|
1804
|
+ full_name += ' (IO Manager: {})'.format(io_manager)
|
|
1741
|
1805
|
test_n = len(allTestNames)
|
|
1742
|
1806
|
progress_args = [ full_name, t.total_tests, test_n,
|
|
1743
|
1807
|
[len(t.unexpected_passes),
|
| ... |
... |
@@ -1818,7 +1882,20 @@ async def do_test(name: TestName, |
|
1818
|
1882
|
# Don't continue and try to run the test if the pre_cmd fails.
|
|
1819
|
1883
|
return
|
|
1820
|
1884
|
|
|
1821
|
|
- result = await func(*[name,way] + args)
|
|
|
1885
|
+
|
|
|
1886
|
+ func_has_io_manager_param = func in [
|
|
|
1887
|
+ backpack_run,
|
|
|
1888
|
+ compile_and_run,
|
|
|
1889
|
+ ghci_multiunit_script,
|
|
|
1890
|
+ ghci_script,
|
|
|
1891
|
+ multi_compile_and_run,
|
|
|
1892
|
+ multimod_compile_and_run,
|
|
|
1893
|
+ warn_and_run
|
|
|
1894
|
+ ]
|
|
|
1895
|
+
|
|
|
1896
|
+ io_manager_arg = [io_manager] if func_has_io_manager_param else []
|
|
|
1897
|
+
|
|
|
1898
|
+ result = await func(*[name,way] + io_manager_arg + args)
|
|
1822
|
1899
|
|
|
1823
|
1900
|
if opts.expect not in ['pass', 'fail', 'missing-lib']:
|
|
1824
|
1901
|
framework_fail(name, way, 'bad expected ' + opts.expect)
|
| ... |
... |
@@ -1907,7 +1984,7 @@ def framework_warn(name: TestName, way: WayName, reason: str) -> None: |
|
1907
|
1984
|
# run_command.
|
|
1908
|
1985
|
|
|
1909
|
1986
|
async def run_command( name, way, cmd ):
|
|
1910
|
|
- return await simple_run( name, WayName(''), override_options(cmd), '' )
|
|
|
1987
|
+ return await simple_run( name, WayName(''), None, override_options(cmd), '' )
|
|
1911
|
1988
|
|
|
1912
|
1989
|
async def makefile_test( name, way, target=None ):
|
|
1913
|
1990
|
if target is None:
|
| ... |
... |
@@ -1919,7 +1996,7 @@ async def makefile_test( name, way, target=None ): |
|
1919
|
1996
|
# -----------------------------------------------------------------------------
|
|
1920
|
1997
|
# GHCi tests
|
|
1921
|
1998
|
|
|
1922
|
|
-async def ghci_script( name, way, script):
|
|
|
1999
|
+async def ghci_script( name, way, io_manager, script):
|
|
1923
|
2000
|
flags = ' '.join(get_compiler_flags())
|
|
1924
|
2001
|
way_flags = ' '.join(config.way_flags[way])
|
|
1925
|
2002
|
|
| ... |
... |
@@ -1930,9 +2007,9 @@ async def ghci_script( name, way, script): |
|
1930
|
2007
|
# NB: put way_flags before flags so that flags in all.T can override others
|
|
1931
|
2008
|
|
|
1932
|
2009
|
getTestOpts().stdin = script
|
|
1933
|
|
- return await simple_run( name, way, cmd, getTestOpts().extra_run_opts )
|
|
|
2010
|
+ return await simple_run( name, way, io_manager, cmd, getTestOpts().extra_run_opts )
|
|
1934
|
2011
|
|
|
1935
|
|
-async def ghci_multiunit_script( name, way, units, script):
|
|
|
2012
|
+async def ghci_multiunit_script( name, way, io_manager, units, script):
|
|
1936
|
2013
|
flags = ' '.join(get_compiler_flags())
|
|
1937
|
2014
|
way_flags = ' '.join(config.way_flags[way])
|
|
1938
|
2015
|
unit_flags = ' '.join(['-unit @%s' % unit for unit in units])
|
| ... |
... |
@@ -1944,7 +2021,7 @@ async def ghci_multiunit_script( name, way, units, script): |
|
1944
|
2021
|
# NB: put way_flags before flags so that flags in all.T can override others
|
|
1945
|
2022
|
|
|
1946
|
2023
|
getTestOpts().stdin = script
|
|
1947
|
|
- return await simple_run( name, way, cmd, getTestOpts().extra_run_opts )
|
|
|
2024
|
+ return await simple_run( name, way, io_manager, cmd, getTestOpts().extra_run_opts )
|
|
1948
|
2025
|
|
|
1949
|
2026
|
# -----------------------------------------------------------------------------
|
|
1950
|
2027
|
# Compile-only tests
|
| ... |
... |
@@ -2124,7 +2201,8 @@ async def compile_grep_core(name: TestName, |
|
2124
|
2201
|
|
|
2125
|
2202
|
async def compile_and_run__(name: TestName,
|
|
2126
|
2203
|
way: WayName,
|
|
2127
|
|
- top_mod: Path | None,
|
|
|
2204
|
+ io_manager: Optional[str],
|
|
|
2205
|
+ top_mod: Optional[Path],
|
|
2128
|
2206
|
extra_mods: List[str],
|
|
2129
|
2207
|
extra_hc_opts: str,
|
|
2130
|
2208
|
backpack: bool=False,
|
| ... |
... |
@@ -2166,22 +2244,22 @@ async def compile_and_run__(name: TestName, |
|
2166
|
2244
|
cmd = './' + name + extension
|
|
2167
|
2245
|
|
|
2168
|
2246
|
# we don't check the compiler's stderr for a compile-and-run test
|
|
2169
|
|
- return await simple_run( name, way, cmd, getTestOpts().extra_run_opts )
|
|
|
2247
|
+ return await simple_run( name, way, io_manager, cmd, getTestOpts().extra_run_opts )
|
|
2170
|
2248
|
|
|
2171
|
|
-async def compile_and_run( name, way, extra_hc_opts ):
|
|
2172
|
|
- return await compile_and_run__( name, way, None, [], extra_hc_opts)
|
|
|
2249
|
+async def compile_and_run( name, way, io_manager, extra_hc_opts ):
|
|
|
2250
|
+ return await compile_and_run__( name, way, io_manager, None, [], extra_hc_opts)
|
|
2173
|
2251
|
|
|
2174
|
|
-async def backpack_run( name, way, extra_hc_opts ):
|
|
2175
|
|
- return await compile_and_run__( name, way, None, [], extra_hc_opts, backpack=True )
|
|
|
2252
|
+async def backpack_run( name, way, io_manager, extra_hc_opts ):
|
|
|
2253
|
+ return await compile_and_run__( name, way, io_manager, None, [], extra_hc_opts, backpack=True )
|
|
2176
|
2254
|
|
|
2177
|
|
-async def multimod_compile_and_run( name, way, top_mod, extra_hc_opts ):
|
|
2178
|
|
- return await compile_and_run__( name, way, top_mod, [], extra_hc_opts)
|
|
|
2255
|
+async def multimod_compile_and_run( name, way, io_manager, top_mod, extra_hc_opts ):
|
|
|
2256
|
+ return await compile_and_run__( name, way, io_manager, top_mod, [], extra_hc_opts)
|
|
2179
|
2257
|
|
|
2180
|
|
-async def multi_compile_and_run( name, way, top_mod, extra_mods, extra_hc_opts ):
|
|
2181
|
|
- return await compile_and_run__( name, way, top_mod, extra_mods, extra_hc_opts)
|
|
|
2258
|
+async def multi_compile_and_run( name, way, io_manager, top_mod, extra_mods, extra_hc_opts ):
|
|
|
2259
|
+ return await compile_and_run__( name, way, io_manager, top_mod, extra_mods, extra_hc_opts)
|
|
2182
|
2260
|
|
|
2183
|
|
-async def warn_and_run( name, way, extra_hc_opts ):
|
|
2184
|
|
- return await compile_and_run__( name, way, None, [], extra_hc_opts, compile_stderr = True)
|
|
|
2261
|
+async def warn_and_run( name, way, io_manager, extra_hc_opts ):
|
|
|
2262
|
+ return await compile_and_run__( name, way, io_manager, None, [], extra_hc_opts, compile_stderr = True)
|
|
2185
|
2263
|
|
|
2186
|
2264
|
async def static_stats( name, way ):
|
|
2187
|
2265
|
opts = getTestOpts()
|
| ... |
... |
@@ -2388,7 +2466,7 @@ async def simple_build(name: Union[TestName, str], |
|
2388
|
2466
|
# from /dev/null. Route output to testname.run.stdout and
|
|
2389
|
2467
|
# testname.run.stderr. Returns the exit code of the run.
|
|
2390
|
2468
|
|
|
2391
|
|
-async def simple_run(name: TestName, way: WayName, prog: str, extra_run_opts: str) -> Any:
|
|
|
2469
|
+async def simple_run(name: TestName, way: WayName, io_manager: Optional[str], prog: str, extra_run_opts: str) -> Any:
|
|
2392
|
2470
|
opts = getTestOpts()
|
|
2393
|
2471
|
|
|
2394
|
2472
|
# figure out what to use for stdin
|
| ... |
... |
@@ -2407,6 +2485,9 @@ async def simple_run(name: TestName, way: WayName, prog: str, extra_run_opts: st |
|
2407
|
2485
|
|
|
2408
|
2486
|
my_rts_flags = rts_flags(way)
|
|
2409
|
2487
|
|
|
|
2488
|
+ if io_manager is not None:
|
|
|
2489
|
+ my_rts_flags += ' +RTS --io-manager={0} -RTS '.format(io_manager)
|
|
|
2490
|
+
|
|
2410
|
2491
|
# Collect runtime stats if necessary:
|
|
2411
|
2492
|
# isStatsTest and not isCompilerStatsTest():
|
|
2412
|
2493
|
# assume we are running a ghc compiled program. Collect stats.
|
| ... |
... |
@@ -2432,6 +2513,12 @@ async def simple_run(name: TestName, way: WayName, prog: str, extra_run_opts: st |
|
2432
|
2513
|
|
|
2433
|
2514
|
output_file = perfStatsFile(False, name)
|
|
2434
|
2515
|
|
|
|
2516
|
+ # Check that IO Manager is available
|
|
|
2517
|
+ if io_manager is not None:
|
|
|
2518
|
+ available_io_managers = discover_io_managers(prog, opts.testdir)
|
|
|
2519
|
+ if io_manager not in available_io_managers:
|
|
|
2520
|
+ framework_fail(name, way, 'IO Manager {} unexpectedly unavailable (available IO Managers: {}). `-non-threaded`/`-threaded` is only supported through way RTS flags (not manually added via test modifiers/args) when testing over IO Managers.'.format(io_manager, available_io_managers))
|
|
|
2521
|
+
|
|
2435
|
2522
|
# run the command
|
|
2436
|
2523
|
exit_code = await runCmdPerf(opts.compiler_perf_counters, cmd, output_file,
|
|
2437
|
2524
|
working_dir=opts.testdir,
|
| ... |
... |
@@ -2493,7 +2580,7 @@ def rts_flags(way: WayName) -> str: |
|
2493
|
2580
|
async def interpreter_run(name: TestName,
|
|
2494
|
2581
|
way: WayName,
|
|
2495
|
2582
|
extra_hc_opts: str,
|
|
2496
|
|
- top_mod: Path | None
|
|
|
2583
|
+ top_mod: Optional[Path]
|
|
2497
|
2584
|
) -> PassFail:
|
|
2498
|
2585
|
opts = getTestOpts()
|
|
2499
|
2586
|
|