webviewhs icon indicating copy to clipboard operation
webviewhs copied to clipboard

High cpu usage on WHS.withWindowLoop iteration function

Open rainbyte opened this issue 4 years ago • 5 comments

When using WHS.withWindowLoop as explained in the documentation, webviewhs starts to consume a high percentage of CPU (100% load almost all the time the app is running).

I have managed to find that the problem is related to the iteration function passed to WHS.withWindowLoop.

As a workaround I have changed (\window -> pure True) to (\window -> threadDelay 8333 $> True), so it updates at ~120fps.

I think my workaround is not the ideal solution. Is there other expected (undocumented) way to handle this or is it a bug?

rainbyte avatar Dec 17 '19 06:12 rainbyte

It is also possible to regulate how much time to wait, but it is still just a workaround

windowIteration lastTimeRef window = do
  currTime <- getCurrentTime
  lastTime <- readIORef lastTimeRef
  writeIORef lastTimeRef currTime
  let dtFloat = (realToFrac $ diffUTCTime currTime lastTime) :: Double
      dtMsecs = floor $ dtFloat * 1000000
      nextFrame = 8333 - rem dtMsecs 8333
  threadDelay nextFrame
  pure True

rainbyte avatar Dec 17 '19 08:12 rainbyte

Hello @rainbyte,

threadDelay, like you've shown, would be the way to loosen such a tight loop. Otherwise, the loop will consume as many CPU cycles as it can.

I would say it's up to the application to control how fast it runs but I could incorporate some convenient, configurable throttling mechanism into the API if you'd like.

If you need total control over the loop there is iterateWindowLoop. You would use that instead of withWindowLoop as that's what withWindowLoop uses. With iterateWindowLoop, your application can run one iteration of the webview when it needs to. For example, you could stop processing the webview while some computation runs on the Haskell side.

:+1:

lettier avatar Dec 18 '19 00:12 lettier

I saw the iterateWindowLoop when reading the withWindowLoop implementation, so I copied the code, simplified it a little bit, and changed it to add the fps handling by hand.

Thanks for the confirmation. Using iterateWindowLoop seems to be the way to go, because it is more flexible. Maybe it could be mentioned in the main documentation.

Having withWindowLoop just for small examples is good too. What about adding a default framerate to it without changing the api or at least a warning?

rainbyte avatar Dec 20 '19 05:12 rainbyte

Hello @rainbyte

I'll add some mild throttling to withWindowLoop.

:+1:

lettier avatar Dec 26 '19 06:12 lettier

@lettier , that would be nice.

I have also created a PR adding an iterate example to the documentation.

rainbyte avatar Dec 26 '19 12:12 rainbyte