GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2020-07-21T15:28:13Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/16012set/getAllocationCounter is broken in GHCi2020-07-21T15:28:13ZAndreas Klebingerset/getAllocationCounter is broken in GHCiIt doesn't seem obvious why it shouldn't work in GHCi, hence the report.
```
Prelude System.Mem> getAllocationCounter
9223372036854757447
Prelude System.Mem> setAllocationCounter 0
()
Prelude System.Mem> getAllocationCounter
92233720368...It doesn't seem obvious why it shouldn't work in GHCi, hence the report.
```
Prelude System.Mem> getAllocationCounter
9223372036854757447
Prelude System.Mem> setAllocationCounter 0
()
Prelude System.Mem> getAllocationCounter
9223372036854758855
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"set/getAllocationCounter is broken in GHCi","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"It doesn't seem obvious why it shouldn't work in GHCi, hence the report.\r\n\r\n{{{\r\nPrelude System.Mem> getAllocationCounter\r\n9223372036854757447\r\nPrelude System.Mem> setAllocationCounter 0\r\n()\r\nPrelude System.Mem> getAllocationCounter\r\n9223372036854758855\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->9.0.1Roland SennRoland Sennhttps://gitlab.haskell.org/ghc/ghc/-/issues/16011GHCi leaks memory even with -fno-it.2019-07-31T14:05:28ZAndreas KlebingerGHCi leaks memory even with -fno-it.GHCi leaks are not exactly new, but this one is especially easy to trigger/reproduce.
The memory allocated by f never gets freed.
```
PS E:\binary-perf> ..\ghc-8.6.1\bin\ghci.exe -fno-it
GHCi, version 8.6.1: http://www.haskell.org/ghc/...GHCi leaks are not exactly new, but this one is especially easy to trigger/reproduce.
The memory allocated by f never gets freed.
```
PS E:\binary-perf> ..\ghc-8.6.1\bin\ghci.exe -fno-it
GHCi, version 8.6.1: http://www.haskell.org/ghc/ :? for help
Prelude> f = [1 .. 20000000] :: [Int]
Prelude> length f
20000000
Prelude> f = [1 .. 20000001] :: [Int]
Prelude> length f
20000001
Prelude> f = [1 .. 20000002] :: [Int]
Prelude> length f
20000002
Prelude> f = [1 .. 20000000] :: [Int]
Prelude> length f
20000000
Prelude>
```
Or using head and even simpler:
```
PS E:\binary-perf> ..\ghc_commonAsm\inplace\bin\ghci.exe -fno-it
GHCi, version 8.7.20181207: http://www.haskell.org/ghc/ :? for help
Loaded package environment from E:\binary-perf\.ghc.environment.x86_64-mingw32-8.7.20181207
Prelude> f = replicate 2000000 False
Prelude> length f
2000000
Prelude> f = replicate 2000000 False
Prelude> length f
2000000
Prelude> f = replicate 2000000 False
Prelude> length f
2000000
Prelude> f = replicate 2000000 False
Prelude> length f
```
GHC just keeps using more and more memory when I repeat this.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | GHCi |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHCi leaks memory even with -fno-it.","status":"New","operating_system":"","component":"GHCi","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"GHCi leaks are not exactly new, but this one is especially easy to trigger/reproduce.\r\n\r\nThe memory allocated by f never gets freed.\r\n{{{\r\nPS E:\\binary-perf> ..\\ghc-8.6.1\\bin\\ghci.exe -fno-it\r\nGHCi, version 8.6.1: http://www.haskell.org/ghc/ :? for help\r\nPrelude> f = [1 .. 20000000] :: [Int]\r\nPrelude> length f\r\n20000000\r\nPrelude> f = [1 .. 20000001] :: [Int]\r\nPrelude> length f\r\n20000001\r\nPrelude> f = [1 .. 20000002] :: [Int]\r\nPrelude> length f\r\n20000002\r\nPrelude> f = [1 .. 20000000] :: [Int]\r\nPrelude> length f\r\n20000000\r\nPrelude>\r\n}}}\r\n\r\nOr using head and even simpler:\r\n\r\n{{{\r\nPS E:\\binary-perf> ..\\ghc_commonAsm\\inplace\\bin\\ghci.exe -fno-it\r\nGHCi, version 8.7.20181207: http://www.haskell.org/ghc/ :? for help\r\nLoaded package environment from E:\\binary-perf\\.ghc.environment.x86_64-mingw32-8.7.20181207\r\nPrelude> f = replicate 2000000 False\r\nPrelude> length f\r\n2000000\r\nPrelude> f = replicate 2000000 False\r\nPrelude> length f\r\n2000000\r\nPrelude> f = replicate 2000000 False\r\nPrelude> length f\r\n2000000\r\nPrelude> f = replicate 2000000 False\r\nPrelude> length f\r\n}}}\r\n\r\nGHC just keeps using more and more memory when I repeat this.\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/16010Broken Link in Data.OldList2019-07-07T18:02:02ZSven TennieBroken Link in Data.OldListIn `Data.OldList`:
```haskell
infix 5 \\ -- comment to fool cpp: https://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html#cpp-string-gaps
```
Looks like the URL changed to: https://downloads.haskell.org/\~ghc/latest...In `Data.OldList`:
```haskell
infix 5 \\ -- comment to fool cpp: https://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html#cpp-string-gaps
```
Looks like the URL changed to: https://downloads.haskell.org/\~ghc/latest/docs/html/users_guide/phases.html\#cpp-and-string-gaps
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.7 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | lowest |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Broken Link in Data.OldList","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"In `Data.OldList`:\r\n{{{\r\n#!haskell\r\ninfix 5 \\\\ -- comment to fool cpp: https://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html#cpp-string-gaps\r\n}}}\r\n\r\nLooks like the URL changed to: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/phases.html#cpp-and-string-gaps","type_of_failure":"OtherFailure","blocking":[]} -->⊥Sven TennieSven Tenniehttps://gitlab.haskell.org/ghc/ghc/-/issues/16009Deprecate `optional` from Text.ParserCombinators.ReadP2020-01-23T19:38:55ZdbaynardDeprecate `optional` from Text.ParserCombinators.ReadPIt seems there is some disagreement on what the type of `optional` should be, within `base`.
`Control.Applicative` defines it as
```haskell
optional :: Alternative f => f a -> f (Maybe a)
```
By contrast, `Text.ParserCombinators.ReadP...It seems there is some disagreement on what the type of `optional` should be, within `base`.
`Control.Applicative` defines it as
```haskell
optional :: Alternative f => f a -> f (Maybe a)
```
By contrast, `Text.ParserCombinators.ReadP` defines it as
```haskell
optional :: ReadP a -> ReadP ()
```
Worse, ReadP implements `Alternative`. So it entirely possible to specialise
```haskell
optional :: ReadP a -> ReadP (Maybe a).
```
In the broader Haskell ecosystem (and beyond) there is further confusion. The `Applicative` definition is used by `parsers`, `megaparsec` and purescript's `Data.Maybe`. The `ReadP` definition is used by `Parsec` and purescript's `Text.Parsing.StringParser`. `Cabal`, like `base` defines both.
I propose to begin to deprecate `ReadP.optional` ASAP, following suggestions in https://www.reddit.com/r/haskell/comments/8cqgds/inconsistent_optional_definitions/. Code which used the old form may still compile; otherwise `void` should be applied.
There have been some suggestions for new names for the `ReadP` definition, such as `optionally` or `optional_`. It may be worth exporting this function directly from `Control.Applicative`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Deprecate `optional` from Text.ParserCombinators.ReadP","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":["Applicative,","Parsers,","ReadP"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"It seems there is some disagreement on what the type of `optional` should be, within `base`.\r\n\r\n`Control.Applicative` defines it as\r\n\r\n{{{#!haskell\r\noptional :: Alternative f => f a -> f (Maybe a)\r\n}}}\r\n\r\nBy contrast, `Text.ParserCombinators.ReadP` defines it as\r\n\r\n{{{#!haskell\r\noptional :: ReadP a -> ReadP ()\r\n}}}\r\n\r\nWorse, ReadP implements `Alternative`. So it entirely possible to specialise\r\n\r\n{{{#!haskell\r\noptional :: ReadP a -> ReadP (Maybe a).\r\n}}}\r\n\r\nIn the broader Haskell ecosystem (and beyond) there is further confusion. The `Applicative` definition is used by `parsers`, `megaparsec` and purescript's `Data.Maybe`. The `ReadP` definition is used by `Parsec` and purescript's `Text.Parsing.StringParser`. `Cabal`, like `base` defines both.\r\n\r\nI propose to begin to deprecate `ReadP.optional` ASAP, following suggestions in https://www.reddit.com/r/haskell/comments/8cqgds/inconsistent_optional_definitions/. Code which used the old form may still compile; otherwise `void` should be applied.\r\n\r\nThere have been some suggestions for new names for the `ReadP` definition, such as `optionally` or `optional_`. It may be worth exporting this function directly from `Control.Applicative`.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16008GHC HEAD type family regression involving invisible arguments2019-07-07T18:02:02ZRyan ScottGHC HEAD type family regression involving invisible argumentsThe following code compiles on GHC 8.0.2 through 8.6.2:
```hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
module Bug where
import Data.Kind
class C k where
type S :: k -> Type
data...The following code compiles on GHC 8.0.2 through 8.6.2:
```hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
module Bug where
import Data.Kind
class C k where
type S :: k -> Type
data D :: Type -> Type
data SD :: forall a. D a -> Type
instance C (D a) where
type S = SD
```
But fails to compile on GHC HEAD (commit 73cce63f33ee80f5095085141df9313ac70d1cfa):
```
$ ~/Software/ghc2/inplace/bin/ghc-stage2 Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:15:3: error:
• Type indexes must match class instance head
Expected: S @(D a)
Actual: S @(D a1)
• In the type instance declaration for ‘S’
In the instance declaration for ‘C (D a)’
|
15 | type S = SD
| ^^^^^^^^^^^
```
This regression prevents [the stitch library](https://cs.brynmawr.edu/~rae/papers/2018/stitch/stitch.tar.gz) from compiling.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 8.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | highest |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC HEAD type family regression involving invisible arguments","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"8.8.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.7","keywords":["TypeFamilies,","TypeInType"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following code compiles on GHC 8.0.2 through 8.6.2:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE ScopedTypeVariables #-}\r\n{-# LANGUAGE TypeFamilies #-}\r\n{-# LANGUAGE TypeInType #-}\r\nmodule Bug where\r\n\r\nimport Data.Kind\r\n\r\nclass C k where\r\n type S :: k -> Type\r\n\r\ndata D :: Type -> Type\r\ndata SD :: forall a. D a -> Type\r\n\r\ninstance C (D a) where\r\n type S = SD\r\n}}}\r\n\r\nBut fails to compile on GHC HEAD (commit 73cce63f33ee80f5095085141df9313ac70d1cfa):\r\n\r\n{{{\r\n$ ~/Software/ghc2/inplace/bin/ghc-stage2 Bug.hs\r\n[1 of 1] Compiling Bug ( Bug.hs, Bug.o )\r\n\r\nBug.hs:15:3: error:\r\n • Type indexes must match class instance head\r\n Expected: S @(D a)\r\n Actual: S @(D a1)\r\n • In the type instance declaration for ‘S’\r\n In the instance declaration for ‘C (D a)’\r\n |\r\n15 | type S = SD\r\n | ^^^^^^^^^^^\r\n}}}\r\n\r\nThis regression prevents [https://cs.brynmawr.edu/~rae/papers/2018/stitch/stitch.tar.gz the stitch library] from compiling.","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/16007Implement `-Os`2019-07-07T18:02:03ZSebastian GrafImplement `-Os`Popular C compilers like GCC or clang allow to optimise for binary size.
Since there are multiple ways in which GHC trades code size for faster programs, it might make sense to follow suit. This ticket is for tracking which optimisation...Popular C compilers like GCC or clang allow to optimise for binary size.
Since there are multiple ways in which GHC trades code size for faster programs, it might make sense to follow suit. This ticket is for tracking which optimisations/hacks in the compiler might be affected.
Feel free to add items to the following list:
- potentially huge impact due to specialisation, liberate case and inlining
- potential of -0.9% due to a second run of common block elimination (#14226)
- +0.1% increase in code size due to known calls instead of re-using generic apply thunks in #16005
- -0.1% due to `-fstg-lift-lams` #9476⊥https://gitlab.haskell.org/ghc/ghc/-/issues/16006Framework failures when validating2019-07-07T18:02:03ZÖmer Sinan AğacanFramework failures when validatingI just tried to validate and got this:
```
Framework failures:
. ./perf/should_run/all.T [] (name 'stats_num_field' is not defined)
```
Tree based on fb669f51b3f2cae79511ac3d1c43939d951b1f69.
<details><summary>Trac metadata</summa...I just tried to validate and got this:
```
Framework failures:
. ./perf/should_run/all.T [] (name 'stats_num_field' is not defined)
```
Tree based on fb669f51b3f2cae79511ac3d1c43939d951b1f69.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Test Suite |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Framework failures when validating","status":"New","operating_system":"","component":"Test Suite","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I just tried to validate and got this:\r\n\r\n{{{\r\nFramework failures:\r\n . ./perf/should_run/all.T [] (name 'stats_num_field' is not defined)\r\n}}}\r\n\r\nTree based on fb669f51b3f2cae79511ac3d1c43939d951b1f69.","type_of_failure":"OtherFailure","blocking":[]} -->8.10.1https://gitlab.haskell.org/ghc/ghc/-/issues/16005Don't use a generic apply thunk for known calls2019-07-07T18:02:03ZSebastian GrafDon't use a generic apply thunk for known callsCurrently, an AP thunk like `sat = f a b c` will not have its own entry
point and info pointer and will instead reuse a generic apply thunk
like `stg_ap_4_upd`.
That's great from a code size perspective, but if `f` is a known
function, ...Currently, an AP thunk like `sat = f a b c` will not have its own entry
point and info pointer and will instead reuse a generic apply thunk
like `stg_ap_4_upd`.
That's great from a code size perspective, but if `f` is a known
function, a specialised entry point with a plain call can be much faster
than figuring out the arity and doing dynamic dispatch.
----
I prepared a patch over at [D5414](https://phabricator.haskell.org/D5414) that fixes this by checking if the arity of `f` is unknown (e.g. 0). If not, it will no longer delegate to a generic apply thunk and generate regular entry code and info tables instead.
No impact on allocations, but on counted instructions and code size. Significant changes to counted instructions:
<table><tr><td>cryptarithm1 </td>
<td> -2.5%</td></tr>
<tr><td>lcss </td>
<td> -2.3%</td></tr>
<tr><td>paraffins </td>
<td> -3.8%</td></tr>
<tr><td>wheel-sieve2 </td>
<td> -3.4%</td></tr>
<tr><td></td>
<td></td></tr>
<tr><td>Min </td>
<td> -3.8%</td></tr>
<tr><td>Max </td>
<td> +0.0%</td></tr>
<tr><td> Geometric Mean </td>
<td> -0.2%</td></tr></table>
And changes to binary size greater than 0.1% (all the other programs, basically):
<table><tr><td> Program </td>
<td>Size </td>
<td> Instrs</td></tr>
<tr><td> anna </td>
<td>+0.3% </td>
<td>-0.2%</td></tr>
<tr><td> expert </td>
<td>+0.2% </td>
<td>-0.0%</td></tr>
<tr><td> fluid </td>
<td>+0.2% </td>
<td>-0.1%</td></tr>
<tr><td> grep </td>
<td>+0.2% </td>
<td>-0.0%</td></tr>
<tr><td> infer </td>
<td>+0.2% </td>
<td>-0.4%</td></tr>
<tr><td> last-piece </td>
<td>+0.2% </td>
<td>-0.1%</td></tr>
<tr><td> lift </td>
<td>+0.2% </td>
<td>-0.0%</td></tr>
<tr><td> paraffins </td>
<td>+0.2% </td>
<td>-3.8%</td></tr>
<tr><td> prolog </td>
<td>+0.2% </td>
<td>-0.1%</td></tr>
<tr><td> scs </td>
<td>+0.3% </td>
<td>-0.0%</td></tr>
<tr><td> transform </td>
<td>+0.2% </td>
<td>-0.2%</td></tr>
<tr><td> veritas </td>
<td>+0.2% </td>
<td>+0.0%</td></tr>
<tr><td></td>
<td></td>
<td></td></tr>
<tr><td> Min </td>
<td>+0.1% </td>
<td>-3.8%</td></tr>
<tr><td> Max </td>
<td>+0.3% </td>
<td>+0.0%</td></tr>
<tr><td> Geometric Mean </td>
<td>+0.1% </td>
<td>-0.2%</td></tr></table>
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Don't use a generic apply thunk for known calls","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"Currently, an AP thunk like `sat = f a b c` will not have its own entry\r\npoint and info pointer and will instead reuse a generic apply thunk\r\nlike `stg_ap_4_upd`.\r\n\r\nThat's great from a code size perspective, but if `f` is a known\r\nfunction, a specialised entry point with a plain call can be much faster\r\nthan figuring out the arity and doing dynamic dispatch.\r\n\r\n----\r\n\r\nI prepared a patch over at Phab:D5414 that fixes this by checking if the arity of `f` is unknown (e.g. 0). If not, it will no longer delegate to a generic apply thunk and generate regular entry code and info tables instead.\r\n\r\nNo impact on allocations, but on counted instructions and code size. Significant changes to counted instructions:\r\n\r\n||cryptarithm1 || -2.5%||\r\n||lcss || -2.3%||\r\n||paraffins || -3.8%||\r\n||wheel-sieve2 || -3.4%||\r\n||||||\r\n||Min || -3.8%||\r\n||Max || +0.0%||\r\n|| Geometric Mean || -0.2%||\r\n\r\nAnd changes to binary size greater than 0.1% (all the other programs, basically):\r\n\r\n|| Program ||Size || Instrs||\r\n|| anna ||+0.3% ||-0.2%||\r\n|| expert ||+0.2% ||-0.0%||\r\n|| fluid ||+0.2% ||-0.1%||\r\n|| grep ||+0.2% ||-0.0%||\r\n|| infer ||+0.2% ||-0.4%||\r\n|| last-piece ||+0.2% ||-0.1%||\r\n|| lift ||+0.2% ||-0.0%||\r\n|| paraffins ||+0.2% ||-3.8%||\r\n|| prolog ||+0.2% ||-0.1%||\r\n|| scs ||+0.3% ||-0.0%||\r\n|| transform ||+0.2% ||-0.2%||\r\n|| veritas ||+0.2% ||+0.0%||\r\n||||||||\r\n|| Min ||+0.1% ||-3.8%||\r\n|| Max ||+0.3% ||+0.0%||\r\n|| Geometric Mean ||+0.1% ||-0.2%||","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/16004Vector performance regression in GHC 8.62019-07-07T18:02:04ZGuillaume BouchardVector performance regression in GHC 8.6Hello.
With the following code, I can observe a performance regression between ghc 8.4 and 8.6:
```haskell
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import qualified Data.Vector.Unboxed.Mutable as Vector
import qualified D...Hello.
With the following code, I can observe a performance regression between ghc 8.4 and 8.6:
```haskell
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import qualified Data.Vector.Unboxed.Mutable as Vector
import qualified Data.Vector.Unboxed as VectorU
import Data.Foldable (for_)
main :: IO ()
main = do
let n = 1000
let vUnmutable :: VectorU.Vector Double = VectorU.generate (n * n) (\i -> fromIntegral i)
v :: Vector.IOVector Double <- VectorU.unsafeThaw vUnmutable
for_ [0..(n - 1)] $ \k -> do
for_ [0..(n - 1)] $ \i -> do
for_ [0..(n - 1)] $ \j -> do
a <- Vector.unsafeRead v (i * n + k)
b <- Vector.unsafeRead v (k * n + j)
c <- Vector.unsafeRead v (i * n + j)
Vector.unsafeWrite v (i * n + j) (min (a + b) c)
```
Built with `-O2` and with / without `-fllvm`. I'm using `vector-0.12.0.1`. Here are the timing results:
GHC 8.2.2
> no llvm: 1.7s
> llvm: 1.0s
GHC 8.4.4
> no llvm: 1.6s
> llvm: 0.9s
GHC 8.6.2
> no llvm: 4.8s
> llvm: 4.3s
I'm using the following bash + nix script to gather theses timings:
```bash
nix-shell -p 'haskell.packages.ghc822.ghcWithPackages(p: [p.vector])' --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench"
nix-shell -p 'haskell.packages.ghc822.ghcWithPackages(p: [p.vector])' -p llvm_39 --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench"
nix-shell -p 'haskell.packages.ghc844.ghcWithPackages(p: [p.vector])' --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench"
nix-shell -p 'haskell.packages.ghc844.ghcWithPackages(p: [p.vector])' -p llvm_5 --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench"
nix-shell -p 'haskell.packages.ghc862.ghcWithPackages(p: [p.vector])' --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench"
nix-shell -p 'haskell.packages.ghc862.ghcWithPackages(p: [p.vector])' -p llvm_6 --run "ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench"
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Vector performance regression in GHC 8.6","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Hello.\r\n\r\nWith the following code, I can observe a performance regression between ghc 8.4 and 8.6:\r\n\r\n\r\n{{{#!haskell\r\n{-# LANGUAGE ScopedTypeVariables #-}\r\nmodule Main where\r\nimport qualified Data.Vector.Unboxed.Mutable as Vector\r\nimport qualified Data.Vector.Unboxed as VectorU\r\n\r\nimport Data.Foldable (for_)\r\n\r\nmain :: IO ()\r\nmain = do\r\n let n = 1000\r\n\r\n let vUnmutable :: VectorU.Vector Double = VectorU.generate (n * n) (\\i -> fromIntegral i)\r\n v :: Vector.IOVector Double <- VectorU.unsafeThaw vUnmutable\r\n\r\n for_ [0..(n - 1)] $ \\k -> do\r\n for_ [0..(n - 1)] $ \\i -> do\r\n for_ [0..(n - 1)] $ \\j -> do\r\n a <- Vector.unsafeRead v (i * n + k)\r\n b <- Vector.unsafeRead v (k * n + j)\r\n c <- Vector.unsafeRead v (i * n + j)\r\n Vector.unsafeWrite v (i * n + j) (min (a + b) c)\r\n}}}\r\n\r\nBuilt with `-O2` and with / without `-fllvm`. I'm using `vector-0.12.0.1`. Here are the timing results:\r\n\r\nGHC 8.2.2\r\n no llvm: 1.7s\r\n llvm: 1.0s\r\nGHC 8.4.4\r\n no llvm: 1.6s\r\n llvm: 0.9s\r\nGHC 8.6.2\r\n no llvm: 4.8s\r\n llvm: 4.3s\r\n\r\nI'm using the following bash + nix script to gather theses timings:\r\n\r\n{{{#!bash\r\nnix-shell -p 'haskell.packages.ghc822.ghcWithPackages(p: [p.vector])' --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench\"\r\nnix-shell -p 'haskell.packages.ghc822.ghcWithPackages(p: [p.vector])' -p llvm_39 --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench\"\r\nnix-shell -p 'haskell.packages.ghc844.ghcWithPackages(p: [p.vector])' --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench\"\r\nnix-shell -p 'haskell.packages.ghc844.ghcWithPackages(p: [p.vector])' -p llvm_5 --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench\"\r\nnix-shell -p 'haskell.packages.ghc862.ghcWithPackages(p: [p.vector])' --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp; time ./FloydBench\"\r\nnix-shell -p 'haskell.packages.ghc862.ghcWithPackages(p: [p.vector])' -p llvm_6 --run \"ghc-pkg list | grep vector; ghc -O2 FloydBench.hs -Wall -fforce-recomp -fllvm; time ./FloydBench\"\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/16003Average and maximum residency numbers in nofib broken2019-07-07T18:02:05ZSebastian GrafAverage and maximum residency numbers in nofib brokenMeasuring average and maximum residency in nofib is currently broken:
```
<<ghc: 55717832 bytes, 32 GCs (29 + 3), 0/0 avg/max bytes residency (0 samples), 58859672 bytes GC work, ...
```
I think that [this line](https://github.com/ghc/...Measuring average and maximum residency in nofib is currently broken:
```
<<ghc: 55717832 bytes, 32 GCs (29 + 3), 0/0 avg/max bytes residency (0 samples), 58859672 bytes GC work, ...
```
I think that [this line](https://github.com/ghc/nofib/blob/f87d446b4e361cc82f219cf78917db9681af69b3/runstdtest/runstdtest.prl#L403) in runstdtest.prl was responsible for matching on `-S` output, but since [this commit](https://phabricator.haskell.org/rNOFIB4e12b05c76e98aa8e32c9f867519c8187e69e12b), we only do `-s` for performance reasons. There's [this bit of outcommented code](https://github.com/ghc/nofib/blob/f87d446b4e361cc82f219cf78917db9681af69b3/runstdtest/runstdtest.prl#L417-L419) that probably does what we want.
It seems that residency numbers were the only metrics depending on `-S`. I don't think there's a way to recover average residency with `-s` alone.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------------- |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | NoFib benchmark suite |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | #5793 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Average and maximum residency numbers in nofib broken","status":"New","operating_system":"","component":"NoFib benchmark suite","related":[5793],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Measuring average and maximum residency in nofib is currently broken:\r\n\r\n{{{\r\n<<ghc: 55717832 bytes, 32 GCs (29 + 3), 0/0 avg/max bytes residency (0 samples), 58859672 bytes GC work, ...\r\n}}}\r\n\r\nI think that [https://github.com/ghc/nofib/blob/f87d446b4e361cc82f219cf78917db9681af69b3/runstdtest/runstdtest.prl#L403 this line] in runstdtest.prl was responsible for matching on `-S` output, but since [https://phabricator.haskell.org/rNOFIB4e12b05c76e98aa8e32c9f867519c8187e69e12b this commit], we only do `-s` for performance reasons. There's [https://github.com/ghc/nofib/blob/f87d446b4e361cc82f219cf78917db9681af69b3/runstdtest/runstdtest.prl#L417-L419 this bit of outcommented code] that probably does what we want.\r\n\r\nIt seems that residency numbers were the only metrics depending on `-S`. I don't think there's a way to recover average residency with `-s` alone.","type_of_failure":"OtherFailure","blocking":[]} -->⊥https://gitlab.haskell.org/ghc/ghc/-/issues/16002Type family equation with wrong name is silently accepted (GHC 8.6+ only)2021-08-21T13:03:51ZRyan ScottType family equation with wrong name is silently accepted (GHC 8.6+ only)Here's a program:
```hs
{-# LANGUAGE TypeFamilies #-}
module TypeFamilies where
data A
type family B (x :: *) :: * where
A x = x
```
One would hope that GHC would reject that nonsensical equation for `B` that references `A`. On GHC ...Here's a program:
```hs
{-# LANGUAGE TypeFamilies #-}
module TypeFamilies where
data A
type family B (x :: *) :: * where
A x = x
```
One would hope that GHC would reject that nonsensical equation for `B` that references `A`. On GHC 7.8 through 8.4, that is the case:
```
$ /opt/ghc/8.4.4/bin/ghci Bug.hs
GHCi, version 8.4.4: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling TypeFamilies ( Bug.hs, interpreted )
Bug.hs:6:3: error:
• Mismatched type name in type family instance.
Expected: B
Actual: A
• In the type family declaration for ‘B’
|
6 | A x = x
| ^^^^^^^
```
But GHC 8.6.2 and HEAD actually //accept// this program! Thankfully, GHC appears to just treat `A x = x` as though you had written `B x = x`, so it's not like this breaks type safety or anything. Still, this most definitely ought to be rejected.
One interesting observation is that `B` having a CUSK appears to be important. If `B` doesn't have a CUSK, as in the following variant:
```hs
{-# LANGUAGE TypeFamilies #-}
module TypeFamilies where
data A
type family B x where
A x = x
```
Then GHC properly catches the mismatched use of `A`:
```
$ /opt/ghc/8.6.2/bin/ghci Bug.hs
GHCi, version 8.6.2: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling TypeFamilies ( Bug.hs, interpreted )
Bug.hs:6:3: error:
• Mismatched type name in type family instance.
Expected: B
Actual: A
• In the type family declaration for ‘B’
|
6 | A x = x
| ^^^^^^^
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Type family equation with wrong name is silently accepted (GHC 8.6+ only)","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.8.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":["TypeFamilies"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Here's a program:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE TypeFamilies #-}\r\nmodule TypeFamilies where\r\n\r\ndata A\r\ntype family B (x :: *) :: * where\r\n A x = x\r\n}}}\r\n\r\nOne would hope that GHC would reject that nonsensical equation for `B` that references `A`. On GHC 7.8 through 8.4, that is the case:\r\n\r\n{{{\r\n$ /opt/ghc/8.4.4/bin/ghci Bug.hs\r\nGHCi, version 8.4.4: http://www.haskell.org/ghc/ :? for help\r\nLoaded GHCi configuration from /home/rgscott/.ghci\r\n[1 of 1] Compiling TypeFamilies ( Bug.hs, interpreted )\r\n\r\nBug.hs:6:3: error:\r\n • Mismatched type name in type family instance.\r\n Expected: B\r\n Actual: A\r\n • In the type family declaration for ‘B’\r\n |\r\n6 | A x = x\r\n | ^^^^^^^\r\n}}}\r\n\r\nBut GHC 8.6.2 and HEAD actually //accept// this program! Thankfully, GHC appears to just treat `A x = x` as though you had written `B x = x`, so it's not like this breaks type safety or anything. Still, this most definitely ought to be rejected.\r\n\r\nOne interesting observation is that `B` having a CUSK appears to be important. If `B` doesn't have a CUSK, as in the following variant:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE TypeFamilies #-}\r\nmodule TypeFamilies where\r\n\r\ndata A\r\ntype family B x where\r\n A x = x\r\n}}}\r\n\r\nThen GHC properly catches the mismatched use of `A`:\r\n\r\n{{{\r\n$ /opt/ghc/8.6.2/bin/ghci Bug.hs\r\nGHCi, version 8.6.2: http://www.haskell.org/ghc/ :? for help\r\nLoaded GHCi configuration from /home/rgscott/.ghci\r\n[1 of 1] Compiling TypeFamilies ( Bug.hs, interpreted )\r\n\r\nBug.hs:6:3: error:\r\n • Mismatched type name in type family instance.\r\n Expected: B\r\n Actual: A\r\n • In the type family declaration for ‘B’\r\n |\r\n6 | A x = x\r\n | ^^^^^^^\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/16001hadrian doesn't support setting intree gmp configuration explicitly2019-07-07T18:02:05ZCarter Schonwaldhadrian doesn't support setting intree gmp configuration explicitly<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------------- |
| Version | 8.6.2 |
| Type | Bug ...<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------------- |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Build System (Hadrian) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"hadrian doesn't support setting intree gmp configuration explicitly","status":"New","operating_system":"","component":"Build System (Hadrian)","related":[],"milestone":"8.8.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/16000Don't suggest Rank2Types and RankNTypes, only the latter2019-07-07T18:02:05ZchessaiDon't suggest Rank2Types and RankNTypes, only the latterCurrently (as of GHC 8.6.2), error messages that suggest RankNTypes also suggest Rank2Types, but Rank2Types are deprecated.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| --------------------...Currently (as of GHC 8.6.2), error messages that suggest RankNTypes also suggest Rank2Types, but Rank2Types are deprecated.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Parser) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Don't suggest Rank2Types and RankNTypes, only the latter","status":"New","operating_system":"","component":"Compiler (Parser)","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"Currently (as of GHC 8.6.2), error messages that suggest RankNTypes also suggest Rank2Types, but Rank2Types are deprecated. ","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/15999Stabilise nofib runtime measurements2020-10-13T09:30:43ZSebastian GrafStabilise nofib runtime measurementsWith [D4989](https://phabricator.haskell.org/D4989) (cf. #15357) having hit `nofib` master, there are still many benchmarks that are unstable in one way or another. I identified three causes for unstability in #5793\##15999. With system ...With [D4989](https://phabricator.haskell.org/D4989) (cf. #15357) having hit `nofib` master, there are still many benchmarks that are unstable in one way or another. I identified three causes for unstability in #5793\##15999. With system overhead mostly out of the equation, there are still two related tasks left:
1. Identify benchmarks with GC wibbles. Plan: Look at how productivity rate changes while increasing gen 0 heap size. A GC-sensitive benchmark should have a non-monotonic or discontinuous productivity-rate-over-nursery-size curve. Then fix these by iterating `main` often enough for the curve to become smooth and monotone.
1. Now, all benchmarks should have monotonically decreasing instruction count for increasing nursery sizes. If not, maybe there's another class of benchmarks I didn't identify yet in #5793. Of these benchmarks, there are a few, like `real/eff/CS`, that still have highly code layout-sensitive runtimes. Fix these 'microbenchmarks' by hiding them behind a flag.⊥https://gitlab.haskell.org/ghc/ghc/-/issues/15998GHC.Event.Thread.eventManager has a lot of indirections2019-07-07T18:02:06ZchessaiGHC.Event.Thread.eventManager has a lot of indirectionsCurrent `eventManager`:
```hs
eventManager :: IORef (IOArray Int (Maybe (ThreadId, EventManager)))
eventManager = unsafePerformIO $ do
...
```
That's a lot of indirections just to grab your thread's event manager.
Consider the followi...Current `eventManager`:
```hs
eventManager :: IORef (IOArray Int (Maybe (ThreadId, EventManager)))
eventManager = unsafePerformIO $ do
...
```
That's a lot of indirections just to grab your thread's event manager.
Consider the following, which I believe would improve the performance of this:
```hs
data UnliftedIORef :: TYPE 'UnliftedRep -> Type where
UnliftedIORef :: MutVar# RealWorld a -> UnliftedIORef a
eventManager :: UnliftedIORef (MutableArray# RealWorld Things)
data Things = Things !ThreadId !EventManager
```
I think the Maybe can be eliminated. I'm unsure. What makes me think it can be is the following snippet:
```hs
getSystemEventManager :: IO (Maybe EventManager)
getSystemEventManager = do
t <- myThreadId
(cap, _) <- threadCapability t
eventManagerArray <- readIORef eventManager
mmgr <- readIOArray eventManagerArray cap
return $ fmap snd mmgr
getSystemEventManager_ :: IO EventManager
getSystemEventManager_ = do
Just mgr <- getSystemEventManager
return mgr
{-# INLINE getSystemEventManager_ #-}
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC.Event.Thread.eventManager has a lot of indirections","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"Current `eventManager`:\r\n\r\n{{{#!hs\r\neventManager :: IORef (IOArray Int (Maybe (ThreadId, EventManager)))\r\neventManager = unsafePerformIO $ do\r\n...\r\n}}}\r\n\r\nThat's a lot of indirections just to grab your thread's event manager.\r\n\r\nConsider the following, which I believe would improve the performance of this:\r\n\r\n{{{#!hs\r\ndata UnliftedIORef :: TYPE 'UnliftedRep -> Type where\r\n UnliftedIORef :: MutVar# RealWorld a -> UnliftedIORef a\r\n\r\neventManager :: UnliftedIORef (MutableArray# RealWorld Things)\r\n\r\ndata Things = Things !ThreadId !EventManager\r\n}}}\r\n\r\nI think the Maybe can be eliminated. I'm unsure. What makes me think it can be is the following snippet:\r\n\r\n{{{#!hs\r\ngetSystemEventManager :: IO (Maybe EventManager)\r\ngetSystemEventManager = do\r\n t <- myThreadId\r\n (cap, _) <- threadCapability t\r\n eventManagerArray <- readIORef eventManager\r\n mmgr <- readIOArray eventManagerArray cap\r\n return $ fmap snd mmgr\r\n\r\ngetSystemEventManager_ :: IO EventManager\r\ngetSystemEventManager_ = do\r\n Just mgr <- getSystemEventManager\r\n return mgr\r\n{-# INLINE getSystemEventManager_ #-}\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/15997EventManager could benefit from Data.Primitive.UnliftedArray2019-07-07T18:02:06ZchessaiEventManager could benefit from Data.Primitive.UnliftedArray```hs
-- | The event manager state.
data EventManager = EventManager
{ emBackend :: !Backend
, emFds :: {-# UNPACK #-} !(Array Int (MVar (IntTable [FdData])))
, emState :: {-# UNPACK #-} !(IORef State)
...```hs
-- | The event manager state.
data EventManager = EventManager
{ emBackend :: !Backend
, emFds :: {-# UNPACK #-} !(Array Int (MVar (IntTable [FdData])))
, emState :: {-# UNPACK #-} !(IORef State)
, emUniqueSource :: {-# UNPACK #-} !UniqueSource
, emControl :: {-# UNPACK #-} !Control
, emLock :: {-# UNPACK #-} !(MVar ())
}
```
the field in question is an `Array Int (MVar (IntTable [FdData]))`.
`EventManager` could instead be:
```hs
type MVarIO = MVar# RealWorld -- type synonym for brevity
-- | The event manager state.
data EventManager = EventManager
{ emBackend :: !Backend
, emFds :: {-# UNPACK #-} !(UnliftedArray (MVarIO (IntTable [FdData])))
, emState :: {-# UNPACK #-} !(IORef State)
, emUniqueSource :: {-# UNPACK #-} !UniqueSource
, emControl :: {-# UNPACK #-} !Control
, emLock :: {-# UNPACK #-} !(MVar ())
}
```
now the `UnliftedArray` contains non-thunks.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"EventManager could benefit from Data.Primitive.UnliftedArray","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"{{{#!hs\r\n-- | The event manager state.\r\ndata EventManager = EventManager\r\n { emBackend :: !Backend\r\n , emFds :: {-# UNPACK #-} !(Array Int (MVar (IntTable [FdData])))\r\n , emState :: {-# UNPACK #-} !(IORef State)\r\n , emUniqueSource :: {-# UNPACK #-} !UniqueSource\r\n , emControl :: {-# UNPACK #-} !Control\r\n , emLock :: {-# UNPACK #-} !(MVar ())\r\n }\r\n}}}\r\n\r\nthe field in question is an `Array Int (MVar (IntTable [FdData]))`.\r\n\r\n`EventManager` could instead be:\r\n\r\n{{{#!hs\r\n\r\ntype MVarIO = MVar# RealWorld -- type synonym for brevity\r\n\r\n-- | The event manager state.\r\ndata EventManager = EventManager\r\n { emBackend :: !Backend\r\n , emFds :: {-# UNPACK #-} !(UnliftedArray (MVarIO (IntTable [FdData])))\r\n , emState :: {-# UNPACK #-} !(IORef State)\r\n , emUniqueSource :: {-# UNPACK #-} !UniqueSource\r\n , emControl :: {-# UNPACK #-} !Control\r\n , emLock :: {-# UNPACK #-} !(MVar ())\r\n }\r\n}}}\r\n\r\nnow the `UnliftedArray` contains non-thunks.","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/15996Add Unlifted List type to base2023-04-01T11:56:26ZchessaiAdd Unlifted List type to base```hs
data UList (a :: TYPE 'UnliftedRep) where
UNil :: UList a
UCons :: a -> UList a -> UList a
```
This would guarantee that values stored inside the list would not be thunks. It would likely live in something like GHC.List.Unlift...```hs
data UList (a :: TYPE 'UnliftedRep) where
UNil :: UList a
UCons :: a -> UList a -> UList a
```
This would guarantee that values stored inside the list would not be thunks. It would likely live in something like GHC.List.Unlifted, since it uses GHC-specific things.
An example of something it might improve is the implementation of Control.Concurrent.QSem.QSem:
```hs
data QSem = QSem !(MVar (Int, [MVar ()], [MVar ()]))
```
this could instead be:
```hs
type MVarIO = MVar# RealWorld -- type synonym for brevity
data QSem = QSem (MVarIO (Int, UList (MVarIO ()), UList (MVarIO ())))
```
Note that in this example the tuple inside the outermost `MVarIO` boxes the `Int` - this tuple could be represented as a datatype which ensures the unboxing on the `Int`.
The main idea here though is that now you can use `MVar#` inside of the `UList`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Add Unlifted List type to base","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"{{{#!hs\r\ndata UList (a :: TYPE 'UnliftedRep) where\r\n UNil :: UList a\r\n UCons :: a -> UList a -> UList a\r\n}}}\r\n\r\nThis would guarantee that values stored inside the list would not be thunks. It would likely live in something like GHC.List.Unlifted, since it uses GHC-specific things.\r\n\r\nAn example of something it might improve is the implementation of Control.Concurrent.QSem.QSem:\r\n\r\n{{{#!hs\r\ndata QSem = QSem !(MVar (Int, [MVar ()], [MVar ()]))\r\n}}}\r\n\r\nthis could instead be:\r\n\r\n{{{#!hs\r\ntype MVarIO = MVar# RealWorld -- type synonym for brevity\r\n\r\ndata QSem = QSem (MVarIO (Int, UList (MVarIO ()), UList (MVarIO ())))\r\n}}}\r\n\r\nNote that in this example the tuple inside the outermost `MVarIO` boxes the `Int` - this tuple could be represented as a datatype which ensures the unboxing on the `Int`.\r\n\r\nThe main idea here though is that now you can use `MVar#` inside of the `UList`.\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/15995Make Control.Concurrent.QSem a newtype2019-07-07T18:02:07ZchessaiMake Control.Concurrent.QSem a newtype```hs
data QSem = QSem !(MVar (Int, [MVar ()], [MVar ()]))
```
I think this should be a newtype. The strictness annotations on the outter `MVar` could just be at each site where pattern matching on the `QSem`.
<details><summary>Trac me...```hs
data QSem = QSem !(MVar (Int, [MVar ()], [MVar ()]))
```
I think this should be a newtype. The strictness annotations on the outter `MVar` could just be at each site where pattern matching on the `QSem`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Make Control.Concurrent.QSem a newtype","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"{{{#!hs\r\ndata QSem = QSem !(MVar (Int, [MVar ()], [MVar ()]))\r\n}}}\r\n\r\nI think this should be a newtype. The strictness annotations on the outter `MVar` could just be at each site where pattern matching on the `QSem`.","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/15994Duplicate entries in -ddump-minimal-imports2019-07-07T18:02:07ZSimon Peyton JonesDuplicate entries in -ddump-minimal-importsConsider
```
module Foo where
import System.IO
f = [ReadMode, ReadMode]
```
We get this:
```
$ ghc -c -ddump-minimal-imports Foo.hs
$ cat Foo.imports
import System.IO ( IOMode(ReadMode, ReadMode) )
```
Notice that `ReadMode` appear...Consider
```
module Foo where
import System.IO
f = [ReadMode, ReadMode]
```
We get this:
```
$ ghc -c -ddump-minimal-imports Foo.hs
$ cat Foo.imports
import System.IO ( IOMode(ReadMode, ReadMode) )
```
Notice that `ReadMode` appears twice.
Turns out this is because of a refactoring in `RnNames`
```
commit 6353efc7694ba8ec86c091918e02595662169ae2
Author: David Eichmann <EichmannD@gmail.com>
Date: Thu Nov 22 14:48:05 2018 -0500
Fix unused-import warnings
This patch fixes a fairly long-standing bug (dating back to 2015) in
RdrName.bestImport, namely
```
(which I wrote -- don't blame David!).
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Duplicate entries in -ddump-minimal-imports","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Consider\r\n{{{\r\nmodule Foo where\r\n\r\nimport System.IO\r\n\r\nf = [ReadMode, ReadMode]\r\n}}}\r\nWe get this:\r\n{{{\r\n$ ghc -c -ddump-minimal-imports Foo.hs\r\n$ cat Foo.imports\r\nimport System.IO ( IOMode(ReadMode, ReadMode) )\r\n}}}\r\nNotice that `ReadMode` appears twice.\r\n\r\nTurns out this is because of a refactoring in `RnNames`\r\n{{{\r\ncommit 6353efc7694ba8ec86c091918e02595662169ae2\r\nAuthor: David Eichmann <EichmannD@gmail.com>\r\nDate: Thu Nov 22 14:48:05 2018 -0500\r\n\r\n Fix unused-import warnings\r\n \r\n This patch fixes a fairly long-standing bug (dating back to 2015) in\r\n RdrName.bestImport, namely\r\n}}}\r\n(which I wrote -- don't blame David!).\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.6.3https://gitlab.haskell.org/ghc/ghc/-/issues/15993Bitwise-oriented semigroup and monoid newtype wrappers for Data.Bits.Bits ins...2021-01-23T21:02:22Zkoz_Bitwise-oriented semigroup and monoid newtype wrappers for Data.Bits.Bits instancesI've found myself needing these often, and given the existence of similar newtypes for directing `(<>)` and `mempty` for a range of other types, these are conspicuous by their absence. Additionally, while `oneBits` isn't technically nece...I've found myself needing these often, and given the existence of similar newtypes for directing `(<>)` and `mempty` for a range of other types, these are conspicuous by their absence. Additionally, while `oneBits` isn't technically necessary, it's a lot more concise than `complement zeroBits`, and I found myself needing it often.
To that end, I've sketched up this implementation. Technically speaking, GND isn't needed, but it means I don't have to repeat myself a lot. These could be made even more concise with `coerce`, but I decided not to do that, since that would require `TypeApplications`. I've limited derivation to methods that are specifically about bitwise operations, rather than stuff like `Num`.
```hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Data.Bits.Extra where
import Data.Bits ( Bits(..)
, FiniteBits(..)
)
-- | Monoid under bitwise AND.
newtype Conj a = Conj { getConj :: a }
deriving (Eq, Bounded, Enum, Bits, FiniteBits)
instance (Bits a) => Semigroup (Conj a) where
(Conj x) <> (Conj y) = Conj (x .&. y)
instance (Bits a) => Monoid (Conj a) where
mempty = Conj . complement $ zeroBits
-- | Monoid under bitwise OR.
newtype Disj a = Disj { getDisj :: a }
deriving (Eq, Bounded, Enum, Bits, FiniteBits)
instance (Bits a) => Semigroup (Disj a) where
(Disj x) <> (Disj y) = Disj (x .|. y)
instance (Bits a) => Monoid (Disj a) where
mempty = Disj zeroBits
-- | Semigroup under bitwise XOR.
newtype Xor a = Xor { getXor :: a }
deriving (Eq, Bounded, Enum, Bits, FiniteBits)
instance (Bits a) => Semigroup (Xor a) where
(Xor x) <> (Xor y) = Xor (x `xor` y)
-- | Semigroup under bitwise \'equality\'; defined as '1' if the corresponding
-- bits match, '0' otherwise.
newtype Iff a = Iff { getIff :: a }
deriving (Eq, Bounded, Enum, Bits, FiniteBits)
instance (Bits a) => Semigroup (Iff a) where
(Iff x) <> (Iff y) = Iff . complement $ (x `xor` y)
-- not strictly necessary, but would be a big help
-- probably should be INLINE
oneBits :: (Bits a) => a
oneBits = complement zeroBits
```
Potentially this could include more, such as instances of `Ord` based on lexicographic ordering on the bits, rather than defaulting to the underlying one (such as the one for `Int`, which I believe is numeric). However, that's a separate issue. I also don't know if these belong in `Data.Bits` or `Data.Semigroup` (or `Data.Monoid` I guess).
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.2 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Bitwise-oriented semigroup and monoid newtype wrappers for Data.Bits.Bits instances","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"8.6.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"I've found myself needing these often, and given the existence of similar newtypes for directing `(<>)` and `mempty` for a range of other types, these are conspicuous by their absence. Additionally, while `oneBits` isn't technically necessary, it's a lot more concise than `complement zeroBits`, and I found myself needing it often.\r\n\r\nTo that end, I've sketched up this implementation. Technically speaking, GND isn't needed, but it means I don't have to repeat myself a lot. These could be made even more concise with `coerce`, but I decided not to do that, since that would require `TypeApplications`. I've limited derivation to methods that are specifically about bitwise operations, rather than stuff like `Num`. \r\n\r\n{{{#!hs\r\n{-# LANGUAGE GeneralizedNewtypeDeriving #-}\r\n\r\nmodule Data.Bits.Extra where\r\n\r\nimport Data.Bits ( Bits(..)\r\n , FiniteBits(..)\r\n )\r\n\r\n-- | Monoid under bitwise AND.\r\nnewtype Conj a = Conj { getConj :: a }\r\n deriving (Eq, Bounded, Enum, Bits, FiniteBits)\r\n\r\ninstance (Bits a) => Semigroup (Conj a) where\r\n (Conj x) <> (Conj y) = Conj (x .&. y)\r\n\r\ninstance (Bits a) => Monoid (Conj a) where\r\n mempty = Conj . complement $ zeroBits\r\n\r\n-- | Monoid under bitwise OR.\r\nnewtype Disj a = Disj { getDisj :: a }\r\n deriving (Eq, Bounded, Enum, Bits, FiniteBits)\r\n\r\ninstance (Bits a) => Semigroup (Disj a) where\r\n (Disj x) <> (Disj y) = Disj (x .|. y)\r\n\r\ninstance (Bits a) => Monoid (Disj a) where\r\n mempty = Disj zeroBits\r\n\r\n-- | Semigroup under bitwise XOR.\r\nnewtype Xor a = Xor { getXor :: a }\r\n deriving (Eq, Bounded, Enum, Bits, FiniteBits)\r\n\r\ninstance (Bits a) => Semigroup (Xor a) where\r\n (Xor x) <> (Xor y) = Xor (x `xor` y)\r\n\r\n-- | Semigroup under bitwise \\'equality\\'; defined as '1' if the corresponding\r\n-- bits match, '0' otherwise.\r\nnewtype Iff a = Iff { getIff :: a }\r\n deriving (Eq, Bounded, Enum, Bits, FiniteBits)\r\n\r\ninstance (Bits a) => Semigroup (Iff a) where\r\n (Iff x) <> (Iff y) = Iff . complement $ (x `xor` y)\r\n\r\n-- not strictly necessary, but would be a big help\r\n-- probably should be INLINE\r\noneBits :: (Bits a) => a\r\noneBits = complement zeroBits\r\n}}}\r\n\r\nPotentially this could include more, such as instances of `Ord` based on lexicographic ordering on the bits, rather than defaulting to the underlying one (such as the one for `Int`, which I believe is numeric). However, that's a separate issue. I also don't know if these belong in `Data.Bits` or `Data.Semigroup` (or `Data.Monoid` I guess).","type_of_failure":"OtherFailure","blocking":[]} -->
---
Update (17/01/2021)
Based on my IRC conversation with @carter and @bgamari, as well as the comments here and on the MR, I've decided that the design will be as follows:
* The names for the newtypes will be `And`, `Ior`, `Xor` and `Iff` (the last subject to change if SIMD instruction names prove to be helpful, but that's unlikely).
* They will live in `Data.Bits`.
* To break the cyclic dep problem, the current `Data.Bits` will become `GHC.Bits`, re-exported from `Data.Bits`.
* `oneBits` will also live in `Data.Bits`.
* `Show, Read` instances for all of the above newtypes will be stock-derived.
I think this is the right choice in light of everything I've seen and heard.9.2.1