lettier / webviewhs

🌐 A Haskell binding to the webview library created by Serge Zaitsev.
https://lettier.github.io/webviewhs
BSD 3-Clause "New" or "Revised" License
125 stars 8 forks source link

High cpu usage on WHS.withWindowLoop iteration function #4

Open rainbyte opened 4 years ago

rainbyte commented 4 years ago

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 commented 4 years ago

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
lettier commented 4 years ago

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:

rainbyte commented 4 years ago

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?

lettier commented 4 years ago

Hello @rainbyte

I'll add some mild throttling to withWindowLoop.

:+1:

rainbyte commented 4 years ago

@lettier , that would be nice.

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