GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T18:51:35Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/7058Add strict version of modifySTRef2019-07-07T18:51:35ZjoeyadamsAdd strict version of modifySTRefWe added strict versions of modifyIORef and atomicModifyIORef recently (see #5926), and STM has [modifyTVar'](http://hackage.haskell.org/packages/archive/stm/latest/doc/html/Control-Concurrent-STM-TVar.html#v:modifyTVar-39-) since stm-2....We added strict versions of modifyIORef and atomicModifyIORef recently (see #5926), and STM has [modifyTVar'](http://hackage.haskell.org/packages/archive/stm/latest/doc/html/Control-Concurrent-STM-TVar.html#v:modifyTVar-39-) since stm-2.3.
This patch adds `modifySTRef'`, mostly copy-pasted from `modifyIORef'`. My ghc currently doesn't build, so I wasn't able to test it.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.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 strict version of modifySTRef","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"We added strict versions of modifyIORef and atomicModifyIORef recently (see #5926), and STM has [http://hackage.haskell.org/packages/archive/stm/latest/doc/html/Control-Concurrent-STM-TVar.html#v:modifyTVar-39- modifyTVar'] since stm-2.3.\r\n\r\nThis patch adds {{{modifySTRef'}}}, mostly copy-pasted from {{{modifyIORef'}}}. My ghc currently doesn't build, so I wasn't able to test it.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/7052Numeric types’ Read instances use exponential CPU/memory2019-07-07T18:51:36ZAnders KaseorgNumeric types’ Read instances use exponential CPU/memoryComputing
> read "1e99999999" :: Int -- returns 0
> read "1e99999999" :: Integer -- returns \[REDACTED\]
> read "1e99999999" :: Float -- returns Infinity
> read "1e99999999" :: Double -- returns Infinity
takes rather a lot of CPU time ...Computing
> read "1e99999999" :: Int -- returns 0
> read "1e99999999" :: Integer -- returns \[REDACTED\]
> read "1e99999999" :: Float -- returns Infinity
> read "1e99999999" :: Double -- returns Infinity
takes rather a lot of CPU time and memory, and adding more digits to the exponent makes it take exponentially more. In some applications, this behavior could be exploitable as a denial of service.
I’m not sure what the right solution is for Integer, but clearly all the other cases should be optimized to produce 0 or Infinity very quickly.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Numeric types’ Read instances use exponential CPU/memory","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Computing\r\n read \"1e99999999\" :: Int -- returns 0\r\n read \"1e99999999\" :: Integer -- returns [REDACTED]\r\n read \"1e99999999\" :: Float -- returns Infinity\r\n read \"1e99999999\" :: Double -- returns Infinity\r\ntakes rather a lot of CPU time and memory, and adding more digits to the exponent makes it take exponentially more. In some applications, this behavior could be exploitable as a denial of service.\r\n\r\nI’m not sure what the right solution is for Integer, but clearly all the other cases should be optimized to produce 0 or Infinity very quickly.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/6121Very poor constant folding2019-07-07T18:52:05Zlennart@augustsson.netVery poor constant foldingGHC seems to lack constant folding for encodeFloat/decodeFloat.
For many examples, compile the numeric-limits package on hackage, or just this snippet:
```
epsilon :: Double
epsilon = r
where r = 1 - encodeFloat (m-1) e
(m, e)...GHC seems to lack constant folding for encodeFloat/decodeFloat.
For many examples, compile the numeric-limits package on hackage, or just this snippet:
```
epsilon :: Double
epsilon = r
where r = 1 - encodeFloat (m-1) e
(m, e) = decodeFloat (1 `asTypeOf` r)
```
This has a very simple value, but GHC refuses to compute it at compile time. This in turn inhibits other constant folding that should be going on.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.4.1 |
| 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":"Very poor constant folding","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"GHC seems to lack constant folding for encodeFloat/decodeFloat.\r\nFor many examples, compile the numeric-limits package on hackage, or just this snippet:\r\n{{{\r\nepsilon :: Double\r\nepsilon = r\r\n where r = 1 - encodeFloat (m-1) e\r\n (m, e) = decodeFloat (1 `asTypeOf` r)\r\n}}}\r\nThis has a very simple value, but GHC refuses to compute it at compile time. This in turn inhibits other constant folding that should be going on.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Ian Lynagh <igloo@earth.li>Ian Lynagh <igloo@earth.li>https://gitlab.haskell.org/ghc/ghc/-/issues/6082Program compiled with 7.4.1 runs many times slower than compiled with 7.2.22019-07-07T18:52:17ZgchrupalaProgram compiled with 7.4.1 runs many times slower than compiled with 7.2.2The morfette program (http://hackage.haskell.org/package/morfette), when compiled with 7.4.1 runs extremely slow: approx. 20x times slower than when compiled with 7.2.1.
To reproduce, install morfette using both compilers, and run it on...The morfette program (http://hackage.haskell.org/package/morfette), when compiled with 7.4.1 runs extremely slow: approx. 20x times slower than when compiled with 7.2.1.
To reproduce, install morfette using both compilers, and run it on the attached \`sample' file.
```
morfette train sample output --iter-pos=10 --iter-lemma=3
```
I attach the output of the profiler for both compilers. It would seem the performance bug is related to code from the modules GramLab.Perceptron.Multiclass and GramLab.Perceptron.Vector
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.4.1 |
| 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":"Program compiled with 7.4.1 runs many times slower than compiled with 7.2.2","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The morfette program (http://hackage.haskell.org/package/morfette), when compiled with 7.4.1 runs extremely slow: approx. 20x times slower than when compiled with 7.2.1.\r\n\r\nTo reproduce, install morfette using both compilers, and run it on the attached `sample' file.\r\n\r\n{{{\r\nmorfette train sample output --iter-pos=10 --iter-lemma=3\r\n}}}\r\n\r\nI attach the output of the profiler for both compilers. It would seem the performance bug is related to code from the modules GramLab.Perceptron.Multiclass and GramLab.Perceptron.Vector\r\n","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1pcapriottipcapriottihttps://gitlab.haskell.org/ghc/ghc/-/issues/5926Add strict versions of modifyIORef and atomicModifyIORef2023-02-20T02:32:24ZjoeyadamsAdd strict versions of modifyIORef and atomicModifyIORefIt is easy to misuse modifyIORef and atomicModifyIORef due to their lack of strictness. For example, if you use an IORef as a counter, use modifyIORef to increment it, and never evaluate the value until the very end, your program will le...It is easy to misuse modifyIORef and atomicModifyIORef due to their lack of strictness. For example, if you use an IORef as a counter, use modifyIORef to increment it, and never evaluate the value until the very end, your program will leak memory, and you may even get a stack overflow:
```
ref <- newIORef 0
replicateM_ 1000000 $ modifyIORef ref (+1)
readIORef ref >>= print
```
Today, I found a [space leak in the tls package](https://github.com/vincenthz/hs-tls/pull/8). Repeatedly calling sendData would leak memory. It didn't take me long to find the cause once I noticed a module named "Measurement" used for gathering connection statistics. It used modifyIORef to update the Measurement structure. When I changed it to this:
```
x <- readIORef (ctxMeasurement ctx)
writeIORef (ctxMeasurement ctx) $! f x
```
the space leak went away.
A more subtle mistake can be made using atomicModifyIORef. Can you spot the problem with this code?
```
atomicModifyIORef ref (\_ -> (new_value, ()))
```
It's not incrementing anything, it's just replacing the value. However, it's still deferring evaluation of the function. This mistake was pointed out in [The Monad.Reader Issue 19](http://themonadreader.files.wordpress.com/2011/10/issue19.pdf), where they suggested the following idiom:
```
x <- atomicModifyIORef ref (\_ -> (new_value, ()))
x `seq` return ()
```
Thus, I believe there should be strict variants of modifyIORef and atomicModifyIORef, if only to warn programmers of these pitfalls.
`modifyIORef'` is pretty straightforward: force the result of applying the function:
```
modifyIORef' ref f = do
x <- readIORef ref
let x' = f x
x' `seq` writeIORef ref x'
```
The only question is: would it be better to force `x'` after `writeIORef` instead of before it, in case a caller is trying to share the IORef among threads (which they shouldn't be)?
`atomicModifyIORef` is less straightforward. Should we force the values themselves? It is possible to avoid the space leak above without forcing either the new value or the return value:
```
atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
atomicModifyIORef' ref f = do
p <- atomicModifyIORef ref (\a -> let p = f a in (fst p, p))
p `seq` return (snd p)
```
It also allows `f` to decide what to force. For example, with this definition of atomicModifyIORef', the following program prints 10000000 and does not leak memory:
```
ref <- newIORef 0
replicateM_ 10000000 $
atomicModifyIORef' ref
(\n -> let n' = n + 1
in n' `seq` (n', undefined))
readIORef ref >>= print
```
In the attached patch, I didn't implement atomicModifyIORef' this way. Instead, I made it force both the old and new values, and added a separate function called atomicWriteIORef that has the same signature as writeIORef, but is based on atomicModifyIORef.
I believe the real value of such functions is to warn programmers about these pitfalls.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.1 |
| 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 strict versions of modifyIORef and atomicModifyIORef","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"It is easy to misuse modifyIORef and atomicModifyIORef due to their lack of strictness. For example, if you use an IORef as a counter, use modifyIORef to increment it, and never evaluate the value until the very end, your program will leak memory, and you may even get a stack overflow:\r\n\r\n{{{\r\nref <- newIORef 0\r\nreplicateM_ 1000000 $ modifyIORef ref (+1)\r\nreadIORef ref >>= print\r\n}}}\r\n\r\nToday, I found a [https://github.com/vincenthz/hs-tls/pull/8 space leak in the tls package]. Repeatedly calling sendData would leak memory. It didn't take me long to find the cause once I noticed a module named \"Measurement\" used for gathering connection statistics. It used modifyIORef to update the Measurement structure. When I changed it to this:\r\n\r\n{{{\r\nx <- readIORef (ctxMeasurement ctx)\r\nwriteIORef (ctxMeasurement ctx) $! f x\r\n}}}\r\n\r\nthe space leak went away.\r\n\r\nA more subtle mistake can be made using atomicModifyIORef. Can you spot the problem with this code?\r\n\r\n{{{\r\natomicModifyIORef ref (\\_ -> (new_value, ()))\r\n}}}\r\n\r\nIt's not incrementing anything, it's just replacing the value. However, it's still deferring evaluation of the function. This mistake was pointed out in [http://themonadreader.files.wordpress.com/2011/10/issue19.pdf The Monad.Reader Issue 19], where they suggested the following idiom:\r\n\r\n{{{\r\nx <- atomicModifyIORef ref (\\_ -> (new_value, ()))\r\nx `seq` return ()\r\n}}}\r\n\r\nThus, I believe there should be strict variants of modifyIORef and atomicModifyIORef, if only to warn programmers of these pitfalls.\r\n\r\n{{{modifyIORef'}}} is pretty straightforward: force the result of applying the function:\r\n\r\n{{{\r\nmodifyIORef' ref f = do\r\n x <- readIORef ref\r\n let x' = f x\r\n x' `seq` writeIORef ref x'\r\n}}}\r\n\r\nThe only question is: would it be better to force `x'` after `writeIORef` instead of before it, in case a caller is trying to share the IORef among threads (which they shouldn't be)?\r\n\r\n{{{atomicModifyIORef}}} is less straightforward. Should we force the values themselves? It is possible to avoid the space leak above without forcing either the new value or the return value:\r\n\r\n{{{\r\natomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b\r\natomicModifyIORef' ref f = do\r\n p <- atomicModifyIORef ref (\\a -> let p = f a in (fst p, p))\r\n p `seq` return (snd p)\r\n}}}\r\n\r\nIt also allows {{{f}}} to decide what to force. For example, with this definition of atomicModifyIORef', the following program prints 10000000 and does not leak memory:\r\n\r\n{{{\r\nref <- newIORef 0\r\nreplicateM_ 10000000 $\r\n atomicModifyIORef' ref\r\n (\\n -> let n' = n + 1\r\n in n' `seq` (n', undefined))\r\nreadIORef ref >>= print\r\n}}}\r\n\r\nIn the attached patch, I didn't implement atomicModifyIORef' this way. Instead, I made it force both the old and new values, and added a separate function called atomicWriteIORef that has the same signature as writeIORef, but is based on atomicModifyIORef.\r\n\r\nI believe the real value of such functions is to warn programmers about these pitfalls.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/5888Performance regression in 7.4.1 compared to 6.12.32019-07-07T18:53:07ZnickiePerformance regression in 7.4.1 compared to 6.12.3Unless I'm doing something really stupid, there seems to be a significant slowdown for some programs between versions 6 and 7.
The bottom line is that the attached program runs in 6.79 sec. with 7.4.1 versus 4.72 sec. in 6.12.3. The scr...Unless I'm doing something really stupid, there seems to be a significant slowdown for some programs between versions 6 and 7.
The bottom line is that the attached program runs in 6.79 sec. with 7.4.1 versus 4.72 sec. in 6.12.3. The script is meant to reproduce the problem in any x86 or x86_64 machine running linux.
The test machine was an Intel Xeon E7340 2.40GHz, 4x4 cores, GNU/Linux 2.6.32-5 (x86_64), but it can be reproduced in other machines too (i386) with similar results.
```
Checking GHC versions
The Glorious Glasgow Haskell Compilation System, version 6.12.3
The Glorious Glasgow Haskell Compilation System, version 7.4.1
Compiling with GHC 6.12.3
/var/tmp/nickie/ghc-bench/usr/bin/ghc-6.12.3 -o ntak6 --make ntak.hs -O2 -optc-O3
[1 of 1] Compiling Main ( ntak.hs, ntak.o )
Linking ntak6 ...
Compiling with GHC 7.4.1
/var/tmp/nickie/ghc-bench/usr/bin/ghc-7.4.1 -o ntak7 --make ntak.hs -O2 -optc-O3 -rtsopts=all
[1 of 1] Compiling Main ( ntak.hs, ntak.o )
Linking ntak7 ...
Running with GHC 6.12.3
./ntak6 +RTS -sstderr
9, hs time = 4.748408 sec
4,738,681,488 bytes allocated in the heap
11,586,848 bytes copied during GC
33,456 bytes maximum residency (1 sample(s))
321,592 bytes maximum slop
2 MB total memory in use (0 MB lost due to fragmentation)
Generation 0: 9038 collections, 0 parallel, 0.06s, 0.07s elapsed
Generation 1: 1 collections, 0 parallel, 0.00s, 0.00s elapsed
INIT time 0.00s ( 0.00s elapsed)
MUT time 4.66s ( 4.68s elapsed)
GC time 0.06s ( 0.07s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 4.73s ( 4.75s elapsed)
%GC time 1.3% (1.5% elapsed)
Alloc rate 1,015,078,645 bytes per MUT second
Productivity 98.6% of total user, 98.2% of total elapsed
4.72 user 0.02 system 0:04.75 elapsed
Running with GHC 7.4.1
9, hs time = 6.82757 sec
5,529,772,976 bytes allocated in the heap
13,357,408 bytes copied during GC
62,904 bytes maximum residency (2 sample(s))
23,080 bytes maximum slop
2 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 10583 colls, 0 par 0.07s 0.08s 0.0000s 0.0000s
Gen 1 2 colls, 0 par 0.00s 0.00s 0.0002s 0.0002s
INIT time 0.00s ( 0.00s elapsed)
MUT time 6.72s ( 6.75s elapsed)
GC time 0.07s ( 0.08s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 6.79s ( 6.83s elapsed)
%GC time 1.1% (1.2% elapsed)
Alloc rate 822,831,578 bytes per MUT second
Productivity 98.9% of total user, 98.4% of total elapsed
6.79 user 0.04 system 0:06.82 elapsed
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.4.1 |
| 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":"Performance regression in 7.4.1 compared to 6.12.3","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Unless I'm doing something really stupid, there seems to be a significant slowdown for some programs between versions 6 and 7.\r\n\r\nThe bottom line is that the attached program runs in 6.79 sec. with 7.4.1 versus 4.72 sec. in 6.12.3. The script is meant to reproduce the problem in any x86 or x86_64 machine running linux.\r\n\r\nThe test machine was an Intel Xeon E7340 2.40GHz, 4x4 cores, GNU/Linux 2.6.32-5 (x86_64), but it can be reproduced in other machines too (i386) with similar results.\r\n\r\n{{{\r\nChecking GHC versions\r\nThe Glorious Glasgow Haskell Compilation System, version 6.12.3\r\nThe Glorious Glasgow Haskell Compilation System, version 7.4.1\r\n\r\nCompiling with GHC 6.12.3\r\n/var/tmp/nickie/ghc-bench/usr/bin/ghc-6.12.3 -o ntak6 --make ntak.hs -O2 -optc-O3\r\n[1 of 1] Compiling Main ( ntak.hs, ntak.o )\r\nLinking ntak6 ...\r\n\r\nCompiling with GHC 7.4.1\r\n/var/tmp/nickie/ghc-bench/usr/bin/ghc-7.4.1 -o ntak7 --make ntak.hs -O2 -optc-O3 -rtsopts=all\r\n[1 of 1] Compiling Main ( ntak.hs, ntak.o )\r\nLinking ntak7 ...\r\n\r\nRunning with GHC 6.12.3\r\n./ntak6 +RTS -sstderr \r\n9, hs time = 4.748408 sec\r\n 4,738,681,488 bytes allocated in the heap\r\n 11,586,848 bytes copied during GC\r\n 33,456 bytes maximum residency (1 sample(s))\r\n 321,592 bytes maximum slop\r\n 2 MB total memory in use (0 MB lost due to fragmentation)\r\n\r\n Generation 0: 9038 collections, 0 parallel, 0.06s, 0.07s elapsed\r\n Generation 1: 1 collections, 0 parallel, 0.00s, 0.00s elapsed\r\n\r\n INIT time 0.00s ( 0.00s elapsed)\r\n MUT time 4.66s ( 4.68s elapsed)\r\n GC time 0.06s ( 0.07s elapsed)\r\n EXIT time 0.00s ( 0.00s elapsed)\r\n Total time 4.73s ( 4.75s elapsed)\r\n\r\n %GC time 1.3% (1.5% elapsed)\r\n\r\n Alloc rate 1,015,078,645 bytes per MUT second\r\n\r\n Productivity 98.6% of total user, 98.2% of total elapsed\r\n\r\n4.72 user 0.02 system 0:04.75 elapsed\r\n\r\nRunning with GHC 7.4.1\r\n9, hs time = 6.82757 sec\r\n 5,529,772,976 bytes allocated in the heap\r\n 13,357,408 bytes copied during GC\r\n 62,904 bytes maximum residency (2 sample(s))\r\n 23,080 bytes maximum slop\r\n 2 MB total memory in use (0 MB lost due to fragmentation)\r\n\r\n Tot time (elapsed) Avg pause Max pause\r\n Gen 0 10583 colls, 0 par 0.07s 0.08s 0.0000s 0.0000s\r\n Gen 1 2 colls, 0 par 0.00s 0.00s 0.0002s 0.0002s\r\n\r\n INIT time 0.00s ( 0.00s elapsed)\r\n MUT time 6.72s ( 6.75s elapsed)\r\n GC time 0.07s ( 0.08s elapsed)\r\n EXIT time 0.00s ( 0.00s elapsed)\r\n Total time 6.79s ( 6.83s elapsed)\r\n\r\n %GC time 1.1% (1.2% elapsed)\r\n\r\n Alloc rate 822,831,578 bytes per MUT second\r\n\r\n Productivity 98.9% of total user, 98.4% of total elapsed\r\n\r\n6.79 user 0.04 system 0:06.82 elapsed\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Ian Lynagh <igloo@earth.li>Ian Lynagh <igloo@earth.li>https://gitlab.haskell.org/ghc/ghc/-/issues/5741openFile should fail if null bytes are in the argument2019-07-07T18:53:48ZVeinoropenFile should fail if null bytes are in the argumentIf the argument to openFile contains a null byte, right now it silently truncates everything after the null byte. This could lead to a vulnerability if the programmer relies on the presence of an extension such as ".cfg" to prevent peopl...If the argument to openFile contains a null byte, right now it silently truncates everything after the null byte. This could lead to a vulnerability if the programmer relies on the presence of an extension such as ".cfg" to prevent people from reading in, say, /etc/passwd.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.2.1 |
| 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":"openFile should fail if null bytes are in the argument","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.2.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"If the argument to openFile contains a null byte, right now it silently truncates everything after the null byte. This could lead to a vulnerability if the programmer relies on the presence of an extension such as \".cfg\" to prevent people from reading in, say, /etc/passwd.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/5598Function quotRem is inefficient2019-07-07T18:54:33ZBoris LykahFunction quotRem is inefficientFunction quotRem gets compiled into two div instructions although div computes both quotient and remainder. This inefficiency exists both with NCG and LLVM backends. Thus, quotRem is at least twice as slow as it could be.
As far as I un...Function quotRem gets compiled into two div instructions although div computes both quotient and remainder. This inefficiency exists both with NCG and LLVM backends. Thus, quotRem is at least twice as slow as it could be.
As far as I understand, quotRem is decomposed into two primops quotInt\# and remInt\# (or quotWord\# and remWord\#) and each of them is compiled independently into code which has div instruction. I propose to add new primops quotRemInt\# and quotRemWord\# to address this flaw.
Please see the sample code and corresponding assembly.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.0.3 |
| 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":"Function quotRem is inefficient","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.0.3","keywords":["division,","performance,","primop"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"Function quotRem gets compiled into two div instructions although div computes both quotient and remainder. This inefficiency exists both with NCG and LLVM backends. Thus, quotRem is at least twice as slow as it could be.\r\n\r\nAs far as I understand, quotRem is decomposed into two primops quotInt# and remInt# (or quotWord# and remWord#) and each of them is compiled independently into code which has div instruction. I propose to add new primops quotRemInt# and quotRemWord# to address this flaw.\r\n\r\nPlease see the sample code and corresponding assembly.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Ian Lynagh <igloo@earth.li>Ian Lynagh <igloo@earth.li>https://gitlab.haskell.org/ghc/ghc/-/issues/5205Control.Monad.forever leaks space2019-07-07T18:56:25Ztakano-akioControl.Monad.forever leaks spaceThe attached program, compiled with GHC 7.0.3, uses up all the memory. It runs in a constant space when compiled with GHC 6.12.3.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| -----------------...The attached program, compiled with GHC 7.0.3, uses up all the memory. It runs in a constant space when compiled with GHC 6.12.3.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.0.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Control.Monad.forever leaks space","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.0.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The attached program, compiled with GHC 7.0.3, uses up all the memory. It runs in a constant space when compiled with GHC 6.12.3.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1pcapriottipcapriottihttps://gitlab.haskell.org/ghc/ghc/-/issues/4138Performance regression in overloading2019-07-07T19:00:25ZSimon MarlowPerformance regression in overloadingThe following program goes 25% slower with HEAD compared to 6.12.3:
```
module Main (main) where
import DeepSeq
main :: IO ()
main = do
rnf [ mk x | x <- [ 1 .. 1024 ] ] `seq` return ()
where
mk :: Float -> [(Float,Float)]
...The following program goes 25% slower with HEAD compared to 6.12.3:
```
module Main (main) where
import DeepSeq
main :: IO ()
main = do
rnf [ mk x | x <- [ 1 .. 1024 ] ] `seq` return ()
where
mk :: Float -> [(Float,Float)]
mk x = [ (x+i,x+i+1) | i <- [ 1 .. 2048] ]
```
using the attached `DeepSeq` module, or indeed the standard `Control.DeepSeq`.
Simon and I diagnosed the problem to be the following dictionary for `NFData (Float,Float)` (this is HEAD):
```
Main.main6 :: DeepSeq.NFData (GHC.Types.Float, GHC.Types.Float)
Main.main6 =
DeepSeq.$fNFData(,)
@ GHC.Types.Float
@ GHC.Types.Float
DeepSeq.$fNFDataFloat
DeepSeq.$fNFDataFloat
```
GHC has not inlined the dictionary function or the arguments here, even though this class is in fact just a single-method dictionary. With 6.12 we got:
```
Main.main6 =
\ (ds_dBc :: (GHC.Types.Float, GHC.Types.Float)) ->
case ds_dBc of _ { (x_awr, y_aws) ->
case x_awr of _ { GHC.Types.F# _ ->
case y_aws of _ { GHC.Types.F# _ -> GHC.Unit.() }
}
}
```
i.e. everything fully inlined and a nice efficient definition.
This is currently affecting parallel programs where we typically use `rnf` quite a lot.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.13 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Performance regression in overloading","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"7.0.1","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"simonpj"},"version":"6.13","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following program goes 25% slower with HEAD compared to 6.12.3:\r\n\r\n{{{\r\nmodule Main (main) where\r\n\r\nimport DeepSeq\r\n\r\nmain :: IO ()\r\nmain = do\r\n rnf [ mk x | x <- [ 1 .. 1024 ] ] `seq` return ()\r\n where\r\n mk :: Float -> [(Float,Float)]\r\n mk x = [ (x+i,x+i+1) | i <- [ 1 .. 2048] ]\r\n}}}\r\n\r\nusing the attached `DeepSeq` module, or indeed the standard `Control.DeepSeq`.\r\n\r\nSimon and I diagnosed the problem to be the following dictionary for `NFData (Float,Float)` (this is HEAD):\r\n\r\n{{{\r\nMain.main6 :: DeepSeq.NFData (GHC.Types.Float, GHC.Types.Float)\r\nMain.main6 =\r\n DeepSeq.$fNFData(,)\r\n @ GHC.Types.Float\r\n @ GHC.Types.Float\r\n DeepSeq.$fNFDataFloat\r\n DeepSeq.$fNFDataFloat\r\n}}}\r\n\r\nGHC has not inlined the dictionary function or the arguments here, even though this class is in fact just a single-method dictionary. With 6.12 we got:\r\n\r\n{{{\r\nMain.main6 =\r\n \\ (ds_dBc :: (GHC.Types.Float, GHC.Types.Float)) ->\r\n case ds_dBc of _ { (x_awr, y_aws) ->\r\n case x_awr of _ { GHC.Types.F# _ ->\r\n case y_aws of _ { GHC.Types.F# _ -> GHC.Unit.() }\r\n }\r\n }\r\n}}}\r\n\r\ni.e. everything fully inlined and a nice efficient definition.\r\n\r\nThis is currently affecting parallel programs where we typically use `rnf` quite a lot.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1pcapriottipcapriottihttps://gitlab.haskell.org/ghc/ghc/-/issues/4065Inconsistent loop performance2019-07-07T19:00:51Zrl@cse.unsw.edu.auInconsistent loop performanceHere are two small benchmarks:
```
import Criterion.Main
foo :: Int -> Int -> Int
foo n k | n <= 0 = k
| otherwise = foo (n-1) (k+1)
bar :: Int -> Int -> Int
bar n k | n == 0 = k
| otherwise = bar (n-1) (k+1)
ma...Here are two small benchmarks:
```
import Criterion.Main
foo :: Int -> Int -> Int
foo n k | n <= 0 = k
| otherwise = foo (n-1) (k+1)
bar :: Int -> Int -> Int
bar n k | n == 0 = k
| otherwise = bar (n-1) (k+1)
main :: IO ()
main = defaultMain [ bench "foo" $ nf (uncurry foo) (20000000,0)
, bench "bar" $ nf (uncurry bar) (20000000,0)
]
```
On my laptop, I consistently get a mean running time of about 36ms for `foo` and about 45ms for `bar`. This is a rather big difference. The Core looks about the same and going via C gives me about 42ms for both loops so this is certainly a code generator problem.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 6.13 |
| 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":"Inconsistent loop performance","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"6.13","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Here are two small benchmarks:\r\n\r\n{{{\r\nimport Criterion.Main\r\n\r\nfoo :: Int -> Int -> Int\r\nfoo n k | n <= 0 = k\r\n | otherwise = foo (n-1) (k+1)\r\n\r\nbar :: Int -> Int -> Int\r\nbar n k | n == 0 = k\r\n | otherwise = bar (n-1) (k+1)\r\n\r\nmain :: IO ()\r\nmain = defaultMain [ bench \"foo\" $ nf (uncurry foo) (20000000,0)\r\n , bench \"bar\" $ nf (uncurry bar) (20000000,0)\r\n ]\r\n}}}\r\n\r\nOn my laptop, I consistently get a mean running time of about 36ms for `foo` and about 45ms for `bar`. This is a rather big difference. The Core looks about the same and going via C gives me about 42ms for both loops so this is certainly a code generator problem.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1