Simon Jakobi pushed to branch wip/sjakobi/T27653 at Glasgow Haskell Compiler / GHC

Commits:

7 changed files:

Changes:

  • libraries/base/tests/all.T
    ... ... @@ -243,7 +243,7 @@ test('T8684', expect_broken(8684), compile_and_run, [''])
    243 243
     test('hWaitForInput-accurate-stdin', [js_broken(22349), expect_broken_for(16535, threaded_ways), req_process], compile_and_run, [''])
    
    244 244
     test('T9826',normal, compile_and_run,[''])
    
    245 245
     test('T9848',
    
    246
    -        [ collect_stats('bytes allocated')
    
    246
    +        [ collect_stats('bytes allocated', 2)
    
    247 247
             , only_ways(['normal'])
    
    248 248
             , js_broken(22261)
    
    249 249
             ],
    

  • testsuite/driver/README.md
    ... ... @@ -35,11 +35,13 @@ differences, and things such as that are not necessary to be considered by the
    35 35
     test writer anymore. This is due to the fact that the test comparison relies
    
    36 36
     entirely on locally collected metrics on the testing machine.
    
    37 37
     
    
    38
    -As such, it is perfectly sufficient to write `collect_stats('all',20)` in the
    
    39
    -".T" files to measure the 3 potential stats that can be collected for that test
    
    40
    -and automatically test them for regressions, failing if there is more than a 20%
    
    41
    -change in any direction. In fact, even that is not necessary as
    
    42
    -`collect_stats()` defaults to 'all', and 20% deviation allowed.
    
    38
    +A test states which metric to measure and how much deviation to allow, e.g.
    
    39
    +`collect_stats('bytes allocated', 2)` in the ".T" files. Such a test fails if
    
    40
    +the metric changes by more than 2% in either direction. To gate several metrics,
    
    41
    +use one `collect_stats` call per metric, so that each gets a tolerance matched
    
    42
    +to its noise profile: allocations are nearly deterministic and support tight
    
    43
    +windows, while the residency metrics need considerably slacker ones (see
    
    44
    +Note [Measuring residency] in testlib.py).
    
    43 45
     
    
    44 46
     The function `collect_compiler_stats()` is completely equivalent in every way to
    
    45 47
     `collect_stats` except that it measures the performance of the compiler itself
    

  • testsuite/driver/testlib.py
    ... ... @@ -24,7 +24,7 @@ import subprocess
    24 24
     from testglobals import config, ghc_env, default_testopts, brokens, t, \
    
    25 25
                             TestRun, TestResult, TestOptions, PerfMetric
    
    26 26
     from testutil import strip_quotes, lndir, link_or_copy_file, passed, \
    
    27
    -                     failBecause, testing_metrics, residency_testing_metrics, \
    
    27
    +                     failBecause, residency_testing_metrics, \
    
    28 28
                          stable_perf_counters, \
    
    29 29
                          PassFail, badResult, str_warn, str_removeprefix
    
    30 30
     from term_color import Color, colored
    
    ... ... @@ -816,28 +816,20 @@ def _collect_generic_stat(name : TestName, opts, metric_infos):
    816 816
     
    
    817 817
     # -----
    
    818 818
     
    
    819
    -# Defaults to "test everything, and only break on extreme cases"
    
    820
    -#
    
    821
    -# The inputs to this function are slightly interesting:
    
    822
    -# metric can be either:
    
    823
    -#     - 'all', in which case all 3 possible metrics are collected and compared.
    
    824
    -#     - The specific metric one wants to use in the test.
    
    825
    -#     - A set of the metrics one wants to use in the test.
    
    826
    -#
    
    827
    -# Deviation defaults to 20% because the goal is correctness over performance.
    
    828
    -# The testsuite should avoid breaking when there is not an actual error.
    
    829
    -# Instead, the testsuite should notify of regressions in a non-breaking manner.
    
    819
    +# metric is either a single metric name or a set of metric names. Use one
    
    820
    +# call per metric so each gets a tolerance matched to its noise profile.
    
    821
    +# See Note [Measuring residency] for the residency metrics.
    
    830 822
     #
    
    831 823
     # collect_compiler_stats is used when the metrics collected are about the compiler.
    
    832 824
     # collect_stats is used in the majority case when the metrics to be collected
    
    833 825
     # are about the performance of the runtime code generated by the compiler.
    
    834
    -def collect_compiler_stats(metric='all',deviation=20):
    
    826
    +def collect_compiler_stats(metric, deviation):
    
    835 827
         def f(name, opts, m=metric, d=deviation):
    
    836 828
             no_lint(name, opts)
    
    837 829
             return _collect_stats(name, opts, m, d, None, True)
    
    838 830
         return f
    
    839 831
     
    
    840
    -def collect_stats(metric='all', deviation=20, static_stats_file=None):
    
    832
    +def collect_stats(metric, deviation, static_stats_file=None):
    
    841 833
         return lambda name, opts, m=metric, d=deviation, s=static_stats_file: _collect_stats(name, opts, m, d, s)
    
    842 834
     
    
    843 835
     def statsFile(comp_test: bool, name: str) -> str:
    
    ... ... @@ -864,12 +856,9 @@ def _collect_stats(name: TestName, opts, metrics, deviation: Optional[int],
    864 856
             # This is a bit weird, though.
    
    865 857
             return
    
    866 858
     
    
    867
    -    # Normalize metrics to a list of strings.
    
    859
    +    # Normalize metrics to a set of strings.
    
    868 860
         if isinstance(metrics, str):
    
    869
    -        if metrics == 'all':
    
    870
    -            metrics = testing_metrics()
    
    871
    -        else:
    
    872
    -            metrics = { metrics }
    
    861
    +        metrics = { metrics }
    
    873 862
     
    
    874 863
         opts.is_stats_test = True
    
    875 864
         if is_compiler_stats_test:
    

  • testsuite/tests/bytecode/TLinkable/all.T
    ... ... @@ -3,7 +3,8 @@
    3 3
     # after they have been loaded into the `LoaderState`.
    
    4 4
     # However, this property is currently not validated automatically.
    
    5 5
     test('LinkableUsage01'
    
    6
    -    , [ collect_compiler_stats('all', 2)
    
    6
    +    , [ collect_compiler_stats('bytes allocated', 2)
    
    7
    +      , collect_compiler_stats('max_bytes_used', 5)
    
    7 8
           , extra_files(['genLinkables.sh', 'BCOTemplate.hs'])
    
    8 9
           , pre_cmd('$MAKE -s --no-print-directory LinkableUsage01_Prep')
    
    9 10
           , req_bco
    
    ... ... @@ -18,7 +19,8 @@ test('LinkableUsage01'
    18 19
     
    
    19 20
     # Performance test for bytecode `Linkable`s.
    
    20 21
     test('LinkableUsage02'
    
    21
    -    , [ collect_compiler_stats('all', 2)
    
    22
    +    , [ collect_compiler_stats('bytes allocated', 2)
    
    23
    +      , collect_compiler_stats('max_bytes_used', 5)
    
    22 24
           , extra_files(['genLinkables.sh', 'BCOTemplate.hs'])
    
    23 25
           , pre_cmd('$MAKE -s --no-print-directory LinkableUsage02_Prep')
    
    24 26
           , req_bco
    

  • testsuite/tests/perf/compiler/all.T
    ... ... @@ -640,13 +640,16 @@ test ('T15164',
    640 640
           ],
    
    641 641
           compile,
    
    642 642
           ['-v0 -O'])
    
    643
    +# T15630/T15630a guard against exponential simplifier blowup when inlining
    
    644
    +# join points (#15630). T15630a is a monomorphic variant that has blown up
    
    645
    +# even when T15630 was fine; see the comment in T15630.hs.
    
    643 646
     test('T15630',
    
    644
    -      [collect_compiler_stats()
    
    647
    +      [collect_compiler_stats('bytes allocated', 2)
    
    645 648
           ],
    
    646 649
           compile,
    
    647 650
           ['-O2'])
    
    648 651
     test('T15630a',
    
    649
    -      [collect_compiler_stats()
    
    652
    +      [collect_compiler_stats('bytes allocated', 2)
    
    650 653
           ],
    
    651 654
           compile,
    
    652 655
           ['-O2'])
    
    ... ... @@ -770,12 +773,19 @@ test ('T9198',
    770 773
           compile,
    
    771 774
           [''])
    
    772 775
     
    
    776
    +# Guards against quadratic demand-analysis cost on wide recursive data
    
    777
    +# types, which manifested as a compile-time memory blowup (#11545).
    
    773 778
     test('T11545',
    
    774
    -     [ collect_compiler_stats('all', 15) ],
    
    779
    +     [ collect_compiler_stats('bytes allocated', 2)
    
    780
    +     , collect_compiler_residency(15) ],
    
    775 781
          compile, ['-O'])
    
    776 782
     
    
    783
    +# Guards against the compile-time memory blowup of #15304, caused by
    
    784
    +# over-keen inlining and demand-analysis memory usage on a module with
    
    785
    +# many wide strict constructors.
    
    777 786
     test('T15304',
    
    778
    -     [ collect_compiler_stats('all', 10) ],
    
    787
    +     [ collect_compiler_stats('bytes allocated', 2)
    
    788
    +     , collect_compiler_residency(10) ],
    
    779 789
          compile, ['-O'])
    
    780 790
     test ('T20049',
    
    781 791
           [ collect_compiler_stats('bytes allocated',2) ],
    
    ... ... @@ -797,8 +807,10 @@ test('T16875', # Testing one hole-fit with a lot in scope for #16875
    797 807
          collect_compiler_runtime(4),
    
    798 808
          compile, ['-fdefer-type-errors -fno-max-valid-hole-fits -package ghc'])
    
    799 809
     
    
    810
    +# Guards against renamer/typechecker allocation regressions on very large
    
    811
    +# generated modules (#20261, a Happy-generated parser).
    
    800 812
     test ('T20261',
    
    801
    -      [collect_compiler_stats('all')],
    
    813
    +      [collect_compiler_stats('bytes allocated', 2)],
    
    802 814
           compile,
    
    803 815
           [''])
    
    804 816
     
    
    ... ... @@ -807,8 +819,7 @@ test ('T20261',
    807 819
     # does not sensibly handle one test acting as both
    
    808 820
     # a compile-time and a run-time performance test
    
    809 821
     test('T21839c',
    
    810
    -    [   collect_compiler_stats('all', 10),
    
    811
    -        collect_compiler_runtime(1),
    
    822
    +    [   collect_compiler_runtime(1),
    
    812 823
             only_ways(['normal'])],
    
    813 824
         compile,
    
    814 825
         ['-O'])
    
    ... ... @@ -874,8 +885,12 @@ test('interpreter_steplocal',
    874 885
          ghci_script,
    
    875 886
          ['interpreter_steplocal.script'])
    
    876 887
     
    
    888
    +# Guards against the compile-time memory blowup of #26425; primarily
    
    889
    +# stresses OccAnal and unfolding performance on a long chain of nested
    
    890
    +# join points and cases.
    
    877 891
     test ('T26425',
    
    878
    -      [ collect_compiler_stats('all',20) ],
    
    892
    +      [ collect_compiler_stats('bytes allocated', 2)
    
    893
    +      , collect_compiler_residency(20) ],
    
    879 894
           compile,
    
    880 895
           ['-O'])
    
    881 896
     
    

  • testsuite/tests/perf/compiler/large-project/all.T
    ... ... @@ -7,7 +7,7 @@ def large_project_makedepend(num):
    7 7
         return test(
    
    8 8
             f'large-project-makedepend-{num}',
    
    9 9
             [
    
    10
    -            collect_compiler_stats('bytes allocated'),
    
    10
    +            collect_compiler_stats('bytes allocated', 10),
    
    11 11
                 pre_cmd(f'./large-project.sh {num}'),
    
    12 12
                 extra_files(['large-project.sh']),
    
    13 13
                 ignore_stderr,
    

  • testsuite/tests/perf/space_leaks/all.T
    1 1
     setTestOpts(js_skip)
    
    2 2
     
    
    3 3
     test('space_leak_001',
    
    4
    -     # This could potentially be replaced with
    
    5
    -     # collect_stats('all',5) to test all 3 with
    
    6
    -     # 5% possible deviation.
    
    7 4
          [ collect_stats('bytes allocated',5),
    
    8 5
           collect_runtime_residency(15),
    
    9 6
           omit_ways(['profasm','profthreaded','threaded1','threaded2',