packages feed

hhlo-0.1.0.0: examples/27-gpu-add.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}

module Main where

import qualified Data.Vector.Storable as V
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T

import HHLO.Core.Types
import HHLO.EDSL.Ops
import HHLO.IR.AST (FuncArg(..), TensorType(..), Module)
import HHLO.IR.Builder
import HHLO.IR.Pretty
import HHLO.Runtime.PJRT.Plugin
import HHLO.Runtime.PJRT.Types
import HHLO.Runtime.Device
import HHLO.Runtime.Compile
import HHLO.Runtime.Execute
import HHLO.Runtime.Buffer

main :: IO ()
main = withPJRTGPU $ \api client -> do
    putStrLn "CUDA plugin loaded."

    -- Enumerate devices
    devs <- addressableDevices api client
    putStrLn $ "Found " ++ show (length devs) ++ " addressable device(s):"
    mapM_ (\d -> do
        did  <- deviceId api d
        kind <- deviceKind api d
        putStrLn $ "  Device " ++ show did ++ " : " ++ kind
      ) devs

    -- Pick the first GPU
    mDev <- defaultGPUDevice api client
    case mDev of
        Nothing -> putStrLn "No GPU found!"
        Just dev -> do
            putStrLn "Running add on GPU..."

            let modu :: Module
                modu = moduleFromBuilder @'[2, 2] @'F32 "main"
                    [ FuncArg "arg0" (TensorType [2, 2] F32)
                    , FuncArg "arg1" (TensorType [2, 2] F32)
                    ]
                    $ do
                        x <- arg
                        y <- arg
                        z <- add x y
                        return z

                mlirText = render modu

            T.putStrLn "--- MLIR ---"
            T.putStrLn mlirText
            T.putStrLn "------------"

            exec <- compile api client mlirText

            let inputA = V.fromList [1, 2, 3, 4] :: V.Vector Float
                inputB = V.fromList [10, 20, 30, 40] :: V.Vector Float

            bufA <- toDeviceOn api client dev inputA [2, 2] bufferTypeF32
            bufB <- toDeviceOn api client dev inputB [2, 2] bufferTypeF32

            [bufOut] <- executeOn api exec dev [bufA, bufB]

            result <- fromDeviceF32 api bufOut 4
            putStrLn $ "Result: " ++ show (V.toList result)
            putStrLn $ "Expected: [11.0,22.0,33.0,44.0]"

            if result == V.fromList [11, 22, 33, 44]
                then putStrLn "GPU smoke test PASSED!"
                else putStrLn "GPU smoke test FAILED!"