haskellghcigloss

Gloss animations jerky and hope to add `-O2` to GHCi


I am trying the gloss package in Haskell and have been able to build and run some examples successfully on windows.

The problem is animations jerky.

From the gloss' official page:

Q: Animations seem jerky.

A: Make sure you're compiling with -O2 -threaded. Without the threaded runtime, the code that manages the frame rate will behave badly. This is because GHC takes too long to reschedule the gloss process after the sleep timer has expired. With the threaded runtime, most simple animations should run at about 100fps, which is our internal frame-rate cap.

Yeah. After adding the ghc-options: -O2 -threaded in my cabal file, the jerky was eliminated (when running the .exe file).

But how to eliminate the jerky in REPL?

I have tried

cabal repl
ghci> :set -threaded
ghci> :set -O2
when making flags consistent: warning:
    Optimization flags are incompatible with the byte-code interpreter; optimiza
tion flags ignored.
ghci> main

It doesn't work, i.e. the animation was still jerk.

It seems that the problem is not just -threaded, but involves -O2.

Is there way to workaround it.

GHC 9.6.3, Gloss 1.13.2.2

Thanks.


Solution

  • Enabling -O2 with the bytecode interpreter

    Since GHC 9.8 you can enable optimisations in GHCi:

    Before GHC 9.8, optimizations were considered too unstable to be used with the bytecode interpreter. This restriction has been lifted, but is still regarded as experimental and guarded by -funoptimized-core-for-interpreter, which is enabled by default. In order to use optimizations, run:

    ghci -fno-unoptimized-core-for-interpreter -O
    

    https://downloads.haskell.org/ghc/9.8.1/docs/users_guide/ghci.html#faq-and-things-to-watch-out-for

    Although there is another warning in the documentation of that flag:

    It is not recommended for normal use and can cause a compiler panic.

    Using -fobject-code to avoid bytecode altogether

    There is also another option if the above is not fast enough. You can use the option -fobject-code to compile the Haskell source files you load to native object code instead of bytecode. This is often faster (and can be combined with -O2 even on older GHC versions), however some GHCi features will not work like breakpoints and viewing non-exported functions.

    More info in the documentation here:

    https://downloads.haskell.org/ghc/9.8.1/docs/users_guide/ghci.html#compiling-to-object-code-inside-ghci

    Use --nonmoving-gc

    On the GHC issue you opened, Matthew Pickering suggested that the cause might be garbage collector pauses, and that indeed is the case.

    GHCi needs to carry around a lot of data to interpret your program, which causes the garbage collector to slow down significantly even for simple programs. The default garbage collector needs to stop the whole program each time it collects garbage and that introduces pauses.

    There is an alternative "non-moving" garbage collector which does not cause such long pauses, but it has less throughput in general. In your case throughput is not that important compared to pause times, so you should use the non-moving GC. You can do that by setting the --nonmoving-gc RTS option:

    cabal repl gloss-hello --repl-options="+RTS --nonmoving-gc -RTS"
    

    This removes all stuttering for me with the gloss-hello example. For more intensive applications you might want to consider combining this with one of the above options.