reflex-frp / reflex-platform

A curated package set and set of tools that let you build Haskell packages so they can run on a variety of platforms. reflex-platform is built on top of the nix package manager.
https://reflex-frp.org
BSD 3-Clause "New" or "Revised" License
723 stars 164 forks source link

profiling a reflex-dom app #238

Open ababkin opened 6 years ago

ababkin commented 6 years ago

A beginner Reflex'er here.

I'm building a log inspection app that will be ingesting large logs (through a websocket) and displaying it in a native/web browser. I'm planning to be using virtualListWithSelection (https://github.com/reflex-frp/reflex-dom/blob/986e1cfb514e8a8832479924166920f783787742/reflex-dom-core/src/Reflex/Dom/Widget/Lazy.hs#L30) to support displaying a lot of entries in a list. Currently I am trying to profile the app to see where it spends most of its CPU time (which the app happily hogs). The problem is that if i run it with app +RTS -p, it runs alright, but to stop the app, I pretty much have to kill the webkit window, which seems to prevent from populating the app.prof file (it stays at 0 size) I would terminate the app normally, but I'm not aware of a way to do that for a reflex-dom app (I suppose FRP apps are meant to be run forever).

Are there any tricks to get this profiling data?

ryantrinkle commented 6 years ago

@ababkin You should be able to do performEvent_ $ (liftIO System.Exit.exitSuccess) <$ someEvent

mightybyte commented 6 years ago

I'm sure others will have different recommendations, but the way I usually optimize things is to figure out which events / dynamics are firing most. I usually do this by thinking about which ones are the most likely suspects and then adding traceDynWith / traceEventWith to them. One big source of slowdowns is when things are firing more than they should. Once you identify which ones are firing too much, you can usually reduce the firings by using holdUniqDyn or holdUniqDynBy.

ababkin commented 6 years ago

Thanks

This is what I've tried:

bodyWidget :: (Reflex t, MonadWidget t m) => UTCTime -> m ()
bodyWidget now = do
  ex <- button "exit"
  performEvent_ $ (liftIO exitSuccess) <$ ex
...

it does look like it should have done the trick, but unfortunately it hasn't. As i press the exit button, the progress seems to stop (i have a timer that feeds the counter, and the counter stops) but both the app exec process and the "app Web content" process are still alive and seem to be just hanging out with minimal CPU utilization. So i still have to close the window manually, and the app.prof is still 0 size afterwards.