Skip to content

runST isn't free

While optimizing some code I discovered that runST isn't free. I had a function on the form:

f ... = ...let x = runST in (f x)...

Manually transforming it into

f ... = runST (g ...)
 where g ... = do
    ...
    x <- ...
    g x
    ...

(The real example is at https://github.com/tibbe/unordered-containers/commit/58b7815a057b3575c58b746d5971d59d806b1333)

improved performance quite a bit on this, already highly tuned, function. Unfortunately, combining all the calls to runST into one and pulling them "up" is not all good. The code is now less modular, has a somewhat over specified evaluation order, and generally looks more imperative.

The cause of the decrease in performance is that runSTRep cannot be inlined, which causes allocation of closures inline in the code (where none should be necessary.)

The comment next to runSTRep explains why it's implemented the way it is, but I wonder if matters could be improved by making it a primop. If we create a fresh state token every time, instead of reusing realWorld#, it should be impossible for mutable structures to let-float and become CAFs (which is what runSTRep tries to avoid.)

Trac metadata
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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information