Opened 7 years ago

Closed 7 years ago

Last modified 6 years ago

#2463 closed bug (invalid)

unsafePerformIO in unused record field affects optimisations

Reported by: claus Owned by:
Priority: normal Milestone:
Component: Compiler Version: 6.9
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Runtime performance bug Test Case:
Blocked By: Blocking:
Related Tickets: Differential Revisions:

Description

I have some code that runs 2x slower or worse than a previous version, for no obvious reasons. In an attempt to root out the cause, I made a copy and started deleting parts of the code, until I noticed that I could trigger the performance difference by whether or not I initialise a record field that is no longer even used in this reduced source!

Further refinement shows that much of the performance difference depends on whether that unused field is initialised using 'unsafePerformIO' (needed to use 'typeRepKey') or 'undefined'.

To reproduce, switch the lines with commented with '-- slow' and '--fast':

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.9.20080514

$ ghc --make -O2 Main
[2 of 3] Compiling GPS              ( GPS.hs, GPS.o )

GPS.hs:29:8:
    Warning: Pattern match(es) are overlapped
             In the definition of `typeRepKey'': typeRepKey' tr = ...
Linking Main.exe ...

$ ./Main.exe >dump
5553600000
"Data.Generics.GPS countStuff: 20 secs"


$ ghc --make -O2 Main
[2 of 3] Compiling GPS              ( GPS.hs, GPS.o )

GPS.hs:29:8:
    Warning: Pattern match(es) are overlapped
             In the definition of `typeRepKey'': typeRepKey' tr = ...
[3 of 3] Compiling Main             ( Main.hs, Main.o )
Linking Main.exe ...

$ ./Main.exe >dump
5553600000
"Data.Generics.GPS countStuff: 11 secs"

'Main' uses 'GPS' and 'CompanyDatatypes' for some benchmarking of a Syb variant, hence the blown-up data structures and Syb imports. Only the code in 'GPS' seems to be directly involved, so perhaps one could achieve the same effect by constructing a non-Syb loop, but I'm reluctant to reduce this further, as the performance impact has started to disappear with shrinking code.

Since the remaining code doesn't actually do much anymore, the issue doesn't seem to be in my code, which is nice. But in the original version, I need that record field, and I need to use 'typeRepKey' via 'unsafePerformIO', so any suggestions for helpful compiler options, etc would be welcome.

Attachments (3)

CompanyDatatypes.hs (1.3 KB) - added by claus 7 years ago.
GPS.hs (1.8 KB) - added by claus 7 years ago.
switch -- slow and -- fast lines in here
Main.hs (843 bytes) - added by claus 7 years ago.

Download all attachments as: .zip

Change History (7)

Changed 7 years ago by claus

Changed 7 years ago by claus

switch -- slow and -- fast lines in here

Changed 7 years ago by claus

comment:1 Changed 7 years ago by claus

  • Resolution set to invalid
  • Status changed from new to closed

Going through the output of -ddump-simpl, it appears that just mentioning unsafePerformIO in the slow version instead of undefined in the fast version is sufficient to prevent a worker/wrapper split for mkQ.

Adding an {-# INLINE mkQ #-} pragma makes the "slow" version as fast as the "fast" one. GHC can't really see that the record field is unused, but it can see that undefined is a lot smaller than anything else, so this is probably not a bug, just unexpected behaviour (I used undefined as a placeholder, not as a blackhole that would swallow its context; will have to use something else next time;-).

comment:2 Changed 7 years ago by simonmar

  • Architecture changed from Unknown to Unknown/Multiple

comment:3 Changed 7 years ago by simonmar

  • Operating System changed from Unknown to Unknown/Multiple

comment:4 Changed 6 years ago by simonmar

  • Type of failure set to Runtime performance bug
Note: See TracTickets for help on using tickets.