packages feed

cuda-0.6.5.1: examples/src/deviceQueryDrv/DeviceQuery.hs

{-# LANGUAGE RecordWildCards #-}

module Main where

import Numeric
import Control.Monad
import Text.Printf
import Text.PrettyPrint

import Foreign.CUDA.Analysis                            as CUDA
import qualified Foreign.CUDA.Driver                    as CUDA


main :: IO ()
main = do
  version       <- CUDA.driverVersion
  printf "CUDA device query (Driver API, statically linked)\n"
  printf "CUDA driver version %d.%d\n" (version`div`1000) ((version`mod`100)`div`10)

  CUDA.initialise []
  numDevices <- CUDA.count

  if numDevices == 0
     then printf "There are no available devices that support CUDA\n"
     else printf "Detected %d CUDA capable device%s\n" numDevices (if numDevices > 1 then "s" else "")

  forM_ [0 .. numDevices-1] $ \n -> do
    deviceProp <- CUDA.props =<< CUDA.device n
    printf "\nDevice %d: %s\n" n (deviceName deviceProp)
    statDevice deviceProp


statDevice :: DeviceProperties -> IO ()
statDevice dev@DeviceProperties{..} =
  let
      DeviceResources{..} = deviceResources dev

      pad v             = take width $ v ++ repeat ' '
      width             = maximum $ map (length . fst) props
      table             = nest 2 $ vcat $ map (\(k,v) -> text (pad k) <+> v) props

      grid (x,y)        = int x <+> char 'x' <+> int y
      cube (x,y,z)      = int x <+> char 'x' <+> int y <+> char 'x' <+> int z

      bool True         = text "Yes"
      bool False        = text "No"

      props =
        [("CUDA capability:",                    text $ show computeCapability)
        ,("CUDA cores:",                         text $ printf "%d cores in %d multiprocessors (%d cores/MP)" (coresPerMP * multiProcessorCount) multiProcessorCount coresPerMP)
        ,("Global memory:",                      text $ showBytes totalGlobalMem)
        ,("Constant memory:",                    text $ showBytes totalConstMem)
        ,("Shared memory per block:",            text $ showBytes sharedMemPerBlock)
        ,("Registers per block:",                int regsPerBlock)
        ,("Warp size:",                          int warpSize)
        ,("Maximum threads per multiprocessor:", int maxThreadsPerMultiProcessor)
        ,("Maximum threads per block:",          int maxThreadsPerBlock)
        ,("Maximum grid dimensions:",            cube maxGridSize)
        ,("Maximum block dimensions:",           cube maxBlockSize)
        ,("GPU clock rate:",                     text . showFreq $ clockRate * 1000)
        ,("Memory clock rate:",                  text . showFreq $ memClockRate * 1000)
        ,("Memory bus width:",                   int memBusWidth <> text "-bit")
        ,("L2 cache size:",                      text $ showBytes cacheMemL2)
        ,("Maximum texture dimensions",          empty)
        ,("  1D:",                               int maxTextureDim1D)
        ,("  2D:",                               grid maxTextureDim2D)
        ,("  3D:",                               cube maxTextureDim3D)
        ,("Texture alignment:",                  text $ showBytes textureAlignment)
        ,("Maximum memory pitch:",               text $ showBytes memPitch)
        ,("Concurrent kernel execution:",        bool concurrentKernels)
        ,("Concurrent copy and execution:",      bool deviceOverlap <> text (printf ", with %d copy engine%s" asyncEngineCount (if asyncEngineCount > 1 then "s" else "")))
        ,("Runtime limit on kernel execution:",  bool kernelExecTimeoutEnabled)
        ,("Integrated GPU sharing host memory:", bool integrated)
        ,("Host page-locked memory mapping:",    bool canMapHostMemory)
        ,("ECC memory support:",                 bool eccEnabled)
        ,("Unified addressing (UVA):",           bool unifiedAddressing)
        ,("PCI bus/location:",                   int (busID pciInfo) <> char '/' <> int (deviceID pciInfo))
        ,("Compute mode:",                       text (show computeMode))
        ]
  in
  putStrLn . render
    $ hang table 4
    $ case computeMode of
        Default          -> text "Multiple host threads can use the device simultaneously"
        Exclusive        -> text "Only one host thread in a process is able to use this device"
        Prohibited       -> text "No host thread can use this device"
        ExclusiveProcess -> text "Multiple threads in one process can use the device simultaneously"


showFreq :: Integral i => i -> String
showFreq x = showFFloatSIBase Nothing 1000 (fromIntegral x :: Double) "Hz"

showBytes :: Integral i => i -> String
showBytes x = showFFloatSIBase (Just 0) 1024 (fromIntegral x :: Double) "B"

showFFloatSIBase :: RealFloat a => Maybe Int -> a -> a -> ShowS
showFFloatSIBase p b n
  = showString
  $ showFFloat p n' (' ':si_unit)
  where
    n'          = n / (b ^^ pow)
    pow         = (-4) `max` floor (logBase b n) `min` 4        :: Int
    si_unit     = case pow of
                       -4 -> "p"
                       -3 -> "n"
                       -2 -> "µ"
                       -1 -> "m"
                       0  -> ""
                       1  -> "k"
                       2  -> "M"
                       3  -> "G"
                       4  -> "T"
                       _  -> error "out of range!"