fjvallarino/monomer

Question: Cuda/Futhark (GPU) image manipulation functions in Monomer, Best Practices

Closed this issue · 4 comments

I'm trying to use Cuda/Futhark image manipulation functions in a Monomer App.

Normally I do this by keeping everything in the same Monad that holds the cuda context as part of it's state but in monomer I can only execute a Task on IO asynchronously.

What is the best design pattern for a monomer program that needs to access a cuda context?

Unfortunately, the obvious answer of creating new contexts, besides one inital one, is too slow.

Thanks for all your help!

UPDATE: I was able to answer my own question with some trial and error, I ended up creating some new recordkeepers used as handlers(CUDAContext, GPUCommand), functions (handleCommand, createHandle) and holding the "GPU context" in a lens (held by app model) which maintains an MVar (Chan GPUCommand); though the secret sauce is a (monad) StateTransformer

Thanks again and very much willing to elaborate if you'd like to write tutorials or a cookbook about using GPU Accelerated Code (CUDA, etc) in Monomer :)

This may not be idiomatic, but when you have something that you initiliaze at the start and then use that for the entire app lifetime, I find a module-level global variable using IORef much better. The module will only export initialize and run functions essentially making the global var private. Of course, in case where you have a lot of env data to pass around, what you did maybe better (or maybe both?).

Hi @MilesLitteral!

I think putting that information in the model is perfectly fine. Alternatively, when I don't want to put that kind of information in the model (mainly because it makes it hard to have the required Eq instance), I create some sort of Env type that I pass as the first parameter to handleEvent and buildUI. For example:

newtype AppEnv = AppEnv {
  _dbServerCtx :: DBServerCtx,
}

handleEvent appEnv wenv node model evt = case evt of
   -- I can access dbServerCtx where needed
   ...

buildUI appEnv wenv model = widgetTree where
   -- A child widget may need to receive it as a parameter; otherwise, it can be omitted
   ...

main :: IO ()
main = do
    -- Create any computationally expensive that requires one-time initialization
    dbCtx <- makeDbCtx
    let appEnv = AppEnv dbCtx
    startApp model (handleEvent appEnv) (buildUI appEnv) config
  where
    config = []
    model = ...

I'll close the issue. In case you feel something is missing, please re-open it or create a new one. Thanks!