diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py index 7ba54da41589db73078131d37f83b6a98b6fda89..9f4f811a652ce4f2572588ccd0026a479c93ce69 100644 --- a/testsuite/driver/testlib.py +++ b/testsuite/driver/testlib.py @@ -748,7 +748,7 @@ def find_so(lib): def find_non_inplace_so(lib): return _find_so(lib,path_from_ghcPkg(lib, "dynamic-library-dirs"),False) -# Define the a generic stat test, which computes the statistic by calling the function +# Define a generic stat test, which computes the statistic by calling the function # given as the third argument. def collect_generic_stat ( metric, deviation, get_stat ): return collect_generic_stats ( { metric: { 'deviation': deviation, 'current': get_stat } } ) @@ -1766,6 +1766,9 @@ async def multi_compile( name, way, top_mod, extra_mods, extra_hc_opts ): async def multi_compile_fail( name, way, top_mod, extra_mods, extra_hc_opts ): return await do_compile( name, way, True, top_mod, extra_mods, [], extra_hc_opts) +async def make_depend( name, way, mods, extra_hc_opts ): + return await do_compile( name, way, False, ' '.join(mods), [], [], extra_hc_opts, mode = '-M') + async def do_compile(name: TestName, way: WayName, should_fail: bool, @@ -2044,7 +2047,9 @@ async def simple_build(name: Union[TestName, str], addsuf: bool, backpack: bool = False, suppress_stdout: bool = False, - filter_with: str = '') -> Any: + filter_with: str = '', + # Override auto-detection of whether to use --make or -c etc. + mode: Optional[str] = None) -> Any: opts = getTestOpts() # Redirect stdout and stderr to the same file @@ -2061,7 +2066,9 @@ async def simple_build(name: Union[TestName, str], else: srcname = Path(name) - if top_mod is not None: + if mode is not None: + to_do = mode + elif top_mod is not None: to_do = '--make ' if link: to_do = to_do + '-o ' + name diff --git a/testsuite/tests/perf/compiler/large-project/all.T b/testsuite/tests/perf/compiler/large-project/all.T new file mode 100644 index 0000000000000000000000000000000000000000..2cd643674a1d9df4216baac24ee1ddd8dab5d883 --- /dev/null +++ b/testsuite/tests/perf/compiler/large-project/all.T @@ -0,0 +1,21 @@ +# These tests are supposed to prevent severe performance regressions when +# operating on projects with unusually large numbers of modules. +# Inefficient algorithms whose complexity depends on the number of modules won't +# be noticed when running the test suite or compiling medium size projects. + +def large_project_makedepend(num): + return test( + f'large-project-makedepend-{num}', + [ + collect_compiler_stats('bytes allocated', 1), + pre_cmd(f'./large-project.sh {num}'), + extra_files(['large-project.sh']), + ignore_stderr, + windows_skip, + ], + make_depend, + [[f'Mod{i:04d}' for i in range(0, num - 1)], ''], + ) + +large_project_makedepend(4000) +large_project_makedepend(10000) diff --git a/testsuite/tests/perf/compiler/large-project/large-project.sh b/testsuite/tests/perf/compiler/large-project/large-project.sh new file mode 100755 index 0000000000000000000000000000000000000000..ad65655f0bafe96807b43bced5f6c299fb174c21 --- /dev/null +++ b/testsuite/tests/perf/compiler/large-project/large-project.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -eu + +total="$1" + +for ((i = 1; i < $total; i++)) +do + # Important to write directly to variables with `-v`, otherwise the script takes a second per 1000 modules + printf -v j "%04d" "$i" + printf -v k "%04d" "$(($i - 1))" + echo -e "module Mod${j} where +import Mod${k} +f_${j} :: () +f_${j} = f_$k" > "Mod${j}.hs" +done + +echo " +module Mod0000 where +f_0000 :: () +f_0000 = () +" > "Mod0000.hs"