cuda 0.7.5.0 → 0.7.5.1
raw patch · 78 files changed
+8113/−8038 lines, 78 filessetup-changed
Files
- Foreign/CUDA.hs +0/−19
- Foreign/CUDA/Analysis.hs +0/−20
- Foreign/CUDA/Analysis/Device.chs +0/−181
- Foreign/CUDA/Analysis/Occupancy.hs +0/−207
- Foreign/CUDA/Driver.hs +0/−238
- Foreign/CUDA/Driver/Context.hs +0/−23
- Foreign/CUDA/Driver/Context/Base.chs +0/−241
- Foreign/CUDA/Driver/Context/Config.chs +0/−297
- Foreign/CUDA/Driver/Context/Peer.chs +0/−131
- Foreign/CUDA/Driver/Context/Primary.chs +0/−170
- Foreign/CUDA/Driver/Device.chs +0/−403
- Foreign/CUDA/Driver/Error.chs +0/−210
- Foreign/CUDA/Driver/Event.chs +0/−163
- Foreign/CUDA/Driver/Exec.chs +0/−380
- Foreign/CUDA/Driver/IPC/Event.chs +0/−140
- Foreign/CUDA/Driver/IPC/Marshal.chs +0/−177
- Foreign/CUDA/Driver/Marshal.chs +0/−1117
- Foreign/CUDA/Driver/Module.hs +0/−20
- Foreign/CUDA/Driver/Module/Base.chs +0/−322
- Foreign/CUDA/Driver/Module/Link.chs +0/−224
- Foreign/CUDA/Driver/Module/Query.chs +0/−108
- Foreign/CUDA/Driver/Profiler.chs +0/−100
- Foreign/CUDA/Driver/Stream.chs +0/−167
- Foreign/CUDA/Driver/Texture.chs +0/−308
- Foreign/CUDA/Driver/Utils.chs +0/−37
- Foreign/CUDA/Internal/C2HS.hs +0/−230
- Foreign/CUDA/Ptr.hs +0/−184
- Foreign/CUDA/Runtime.hs +0/−28
- Foreign/CUDA/Runtime/Device.chs +0/−464
- Foreign/CUDA/Runtime/Error.chs +0/−116
- Foreign/CUDA/Runtime/Event.chs +0/−148
- Foreign/CUDA/Runtime/Exec.chs +0/−276
- Foreign/CUDA/Runtime/Marshal.chs +0/−648
- Foreign/CUDA/Runtime/Stream.chs +0/−115
- Foreign/CUDA/Runtime/Texture.chs +0/−203
- Foreign/CUDA/Runtime/Utils.chs +0/−49
- Foreign/CUDA/Types.chs +0/−155
- Setup.hs +40/−8
- cuda.cabal +8/−6
- examples/src/deviceQueryDrv/DeviceQuery.hs +1/−5
- src/Foreign/CUDA.hs +19/−0
- src/Foreign/CUDA/Analysis.hs +20/−0
- src/Foreign/CUDA/Analysis/Device.chs +196/−0
- src/Foreign/CUDA/Analysis/Occupancy.hs +207/−0
- src/Foreign/CUDA/Driver.hs +238/−0
- src/Foreign/CUDA/Driver/Context.hs +23/−0
- src/Foreign/CUDA/Driver/Context/Base.chs +241/−0
- src/Foreign/CUDA/Driver/Context/Config.chs +297/−0
- src/Foreign/CUDA/Driver/Context/Peer.chs +131/−0
- src/Foreign/CUDA/Driver/Context/Primary.chs +170/−0
- src/Foreign/CUDA/Driver/Device.chs +403/−0
- src/Foreign/CUDA/Driver/Error.chs +212/−0
- src/Foreign/CUDA/Driver/Event.chs +163/−0
- src/Foreign/CUDA/Driver/Exec.chs +380/−0
- src/Foreign/CUDA/Driver/IPC/Event.chs +140/−0
- src/Foreign/CUDA/Driver/IPC/Marshal.chs +177/−0
- src/Foreign/CUDA/Driver/Marshal.chs +1117/−0
- src/Foreign/CUDA/Driver/Module.hs +20/−0
- src/Foreign/CUDA/Driver/Module/Base.chs +322/−0
- src/Foreign/CUDA/Driver/Module/Link.chs +224/−0
- src/Foreign/CUDA/Driver/Module/Query.chs +108/−0
- src/Foreign/CUDA/Driver/Profiler.chs +100/−0
- src/Foreign/CUDA/Driver/Stream.chs +167/−0
- src/Foreign/CUDA/Driver/Texture.chs +308/−0
- src/Foreign/CUDA/Driver/Utils.chs +40/−0
- src/Foreign/CUDA/Internal/C2HS.hs +230/−0
- src/Foreign/CUDA/Ptr.hs +184/−0
- src/Foreign/CUDA/Runtime.hs +28/−0
- src/Foreign/CUDA/Runtime/Device.chs +464/−0
- src/Foreign/CUDA/Runtime/Error.chs +119/−0
- src/Foreign/CUDA/Runtime/Event.chs +148/−0
- src/Foreign/CUDA/Runtime/Exec.chs +276/−0
- src/Foreign/CUDA/Runtime/Marshal.chs +648/−0
- src/Foreign/CUDA/Runtime/Stream.chs +115/−0
- src/Foreign/CUDA/Runtime/Texture.chs +203/−0
- src/Foreign/CUDA/Runtime/Utils.chs +53/−0
- src/Foreign/CUDA/Types.chs +155/−0
- src/Text/Show/Describe.hs +18/−0
− Foreign/CUDA.hs
@@ -1,19 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Top level bindings. By default, expose the C-for-CUDA runtime API bindings,--- as they are slightly more user friendly.--------------------------------------------------------------------------------------module Foreign.CUDA (-- module Foreign.CUDA.Runtime--) where--import Foreign.CUDA.Runtime-
− Foreign/CUDA/Analysis.hs
@@ -1,20 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Analysis--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Meta-module exporting CUDA analysis routines--------------------------------------------------------------------------------------module Foreign.CUDA.Analysis (-- module Foreign.CUDA.Analysis.Device,- module Foreign.CUDA.Analysis.Occupancy--) where--import Foreign.CUDA.Analysis.Device-import Foreign.CUDA.Analysis.Occupancy-
− Foreign/CUDA/Analysis/Device.chs
@@ -1,181 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Analysis.Device--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Common device functions--------------------------------------------------------------------------------------module Foreign.CUDA.Analysis.Device- (- Compute(..), ComputeMode(..),- DeviceProperties(..), DeviceResources(..), Allocation(..), PCI(..),- deviceResources- )- where--#include "cbits/stubs.h"--import Data.Int-import Debug.Trace----- |--- The compute mode the device is currently in----{# enum CUcomputemode as ComputeMode- { underscoreToCase }- with prefix="CU_COMPUTEMODE" deriving (Eq, Show) #}---- |--- GPU compute capability, major and minor revision number respectively.----data Compute = Compute !Int !Int- deriving Eq--instance Show Compute where- show (Compute major minor) = show major ++ "." ++ show minor--instance Ord Compute where- compare (Compute m1 n1) (Compute m2 n2) =- case compare m1 m2 of- EQ -> compare n1 n2- x -> x--{---cap :: Int -> Int -> Double-cap a 0 = fromIntegral a-cap a b = let a' = fromIntegral a in- let b' = fromIntegral b in- a' + b' / max 10 (10^ ((ceiling . logBase 10) b' :: Int))---}---- |--- The properties of a compute device----data DeviceProperties = DeviceProperties- {- deviceName :: !String -- ^ Identifier- , computeCapability :: !Compute -- ^ Supported compute capability- , totalGlobalMem :: !Int64 -- ^ Available global memory on the device in bytes- , totalConstMem :: !Int64 -- ^ Available constant memory on the device in bytes- , sharedMemPerBlock :: !Int64 -- ^ Available shared memory per block in bytes- , regsPerBlock :: !Int -- ^ 32-bit registers per block- , warpSize :: !Int -- ^ Warp size in threads (SIMD width)- , maxThreadsPerBlock :: !Int -- ^ Maximum number of threads per block-#if CUDA_VERSION >= 4000- , maxThreadsPerMultiProcessor :: !Int -- ^ Maximum number of threads per multiprocessor-#endif- , maxBlockSize :: !(Int,Int,Int) -- ^ Maximum size of each dimension of a block- , maxGridSize :: !(Int,Int,Int) -- ^ Maximum size of each dimension of a grid-#if CUDA_VERSION >= 3000- , maxTextureDim1D :: !Int -- ^ Maximum texture dimensions- , maxTextureDim2D :: !(Int,Int)- , maxTextureDim3D :: !(Int,Int,Int)-#endif- , clockRate :: !Int -- ^ Clock frequency in kilohertz- , multiProcessorCount :: !Int -- ^ Number of multiprocessors on the device- , memPitch :: !Int64 -- ^ Maximum pitch in bytes allowed by memory copies-#if CUDA_VERSION >= 4000- , memBusWidth :: !Int -- ^ Global memory bus width in bits- , memClockRate :: !Int -- ^ Peak memory clock frequency in kilohertz-#endif- , textureAlignment :: !Int64 -- ^ Alignment requirement for textures- , computeMode :: !ComputeMode- , deviceOverlap :: !Bool -- ^ Device can concurrently copy memory and execute a kernel-#if CUDA_VERSION >= 3000- , concurrentKernels :: !Bool -- ^ Device can possibly execute multiple kernels concurrently- , eccEnabled :: !Bool -- ^ Device supports and has enabled error correction-#endif-#if CUDA_VERSION >= 4000- , asyncEngineCount :: !Int -- ^ Number of asynchronous engines- , cacheMemL2 :: !Int -- ^ Size of the L2 cache in bytes- , pciInfo :: !PCI -- ^ PCI device information for the device- , tccDriverEnabled :: !Bool -- ^ Whether this is a Tesla device using the TCC driver-#endif- , kernelExecTimeoutEnabled :: !Bool -- ^ Whether there is a runtime limit on kernels- , integrated :: !Bool -- ^ As opposed to discrete- , canMapHostMemory :: !Bool -- ^ Device can use pinned memory-#if CUDA_VERSION >= 4000- , unifiedAddressing :: !Bool -- ^ Device shares a unified address space with the host-#endif-#if CUDA_VERSION >= 5050- , streamPriorities :: !Bool -- ^ Device supports stream priorities-#endif-#if CUDA_VERSION >= 6000- , globalL1Cache :: !Bool -- ^ Device supports caching globals in L1 cache- , localL1Cache :: !Bool -- ^ Device supports caching locals in L1 cache- , managedMemory :: !Bool -- ^ Device supports allocating managed memory on this system- , multiGPUBoard :: !Bool -- ^ Device is on a multi-GPU board- , multiGPUBoardGroupID :: !Int -- ^ Unique identifier for a group of devices associated with the same board-#endif- }- deriving (Show)---data PCI = PCI- {- busID :: !Int, -- ^ PCI bus ID of the device- deviceID :: !Int, -- ^ PCI device ID- domainID :: !Int -- ^ PCI domain ID- }- deriving (Show)----- GPU Hardware Resources----data Allocation = Warp | Block-data DeviceResources = DeviceResources- {- threadsPerWarp :: !Int, -- ^ Warp size- threadsPerMP :: !Int, -- ^ Maximum number of in-flight threads on a multiprocessor- threadBlocksPerMP :: !Int, -- ^ Maximum number of thread blocks resident on a multiprocessor- warpsPerMP :: !Int, -- ^ Maximum number of in-flight warps per multiprocessor- coresPerMP :: !Int, -- ^ Number of SIMD arithmetic units per multiprocessor- sharedMemPerMP :: !Int, -- ^ Total amount of shared memory per multiprocessor (bytes)- sharedMemAllocUnit :: !Int, -- ^ Shared memory allocation unit size (bytes)- regFileSize :: !Int, -- ^ Total number of registers in a multiprocessor- regAllocUnit :: !Int, -- ^ Register allocation unit size- regAllocWarp :: !Int, -- ^ Register allocation granularity for warps- regPerThread :: !Int, -- ^ Maximum number of registers per thread- allocation :: !Allocation -- ^ How multiprocessor resources are divided- }----- |--- Extract some additional hardware resource limitations for a given device.----deviceResources :: DeviceProperties -> DeviceResources-deviceResources = resources . computeCapability- where- -- This is mostly extracted from tables in the CUDA occupancy calculator.- --- resources compute = case compute of- Compute 1 0 -> DeviceResources 32 768 8 24 8 16384 512 8192 256 2 124 Block -- Tesla G80- Compute 1 1 -> DeviceResources 32 768 8 24 8 16384 512 8192 256 2 124 Block -- Tesla G8x- Compute 1 2 -> DeviceResources 32 1024 8 32 8 16384 512 16384 512 2 124 Block -- Tesla G9x- Compute 1 3 -> DeviceResources 32 1024 8 32 8 16384 512 16384 512 2 124 Block -- Tesla GT200- Compute 2 0 -> DeviceResources 32 1536 8 48 32 49152 128 32768 64 2 63 Warp -- Fermi GF100- Compute 2 1 -> DeviceResources 32 1536 8 48 48 49152 128 32768 64 2 63 Warp -- Fermi GF10x- Compute 3 0 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 63 Warp -- Kepler GK10x- Compute 3 2 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 255 Warp -- Jetson TK1- Compute 3 5 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 255 Warp -- Kepler GK11x- Compute 3 7 -> DeviceResources 32 2048 16 64 192 114688 256 131072 256 4 266 Warp -- Kepler GK21x- Compute 5 0 -> DeviceResources 32 2048 32 64 128 65536 256 65536 256 4 255 Warp -- Maxwell GM10x- Compute 5 2 -> DeviceResources 32 2048 32 64 128 98304 256 65536 256 4 255 Warp -- Maxwell GM20x- Compute 5 3 -> DeviceResources 32 2048 32 64 128 65536 256 65536 256 4 255 Warp -- Maxwell GM20B-- -- Something might have gone wrong, or the library just needs to be- -- updated for the next generation of hardware, in which case we just want- -- to pick a sensible default and carry on.- --- -- This is slightly dodgy as the warning message is coming from pure code.- -- However, it should be OK because all library functions run in IO, so it- -- is likely the user code is as well.- --- _ -> trace warning $ resources (Compute 3 0)- where warning = unlines [ "*** Warning: Unknown CUDA device compute capability: " ++ show compute- , "*** Please submit a bug report at https://github.com/tmcdonell/cuda/issues" ]-
− Foreign/CUDA/Analysis/Occupancy.hs
@@ -1,207 +0,0 @@-{-# LANGUAGE BangPatterns #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Analysis.Occupancy--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Occupancy calculations for CUDA kernels------ <http://developer.download.nvidia.com/compute/cuda/3_0/sdk/docs/CUDA_Occupancy_calculator.xls>------ /Determining Registers Per Thread and Shared Memory Per Block/------ To determine the number of registers used per thread in your kernel, simply--- compile the kernel code using the option------ > --ptxas-options=-v------ to nvcc. This will output information about register, local memory, shared--- memory, and constant memory usage for each kernel in the @.cu@ file.--- Alternatively, you can compile with the @-cubin@ option to nvcc. This will--- generate a @.cubin@ file, which you can open in a text editor. Look for the--- @code@ section with your kernel's name. Within the curly braces (@{ ... }@)--- for that code block, you will see a line with @reg = X@, where @x@ is the--- number of registers used by your kernel. You can also see the amount of--- shared memory used as @smem = Y@. However, if your kernel declares any--- external shared memory that is allocated dynamically, you will need to add--- the number in the @.cubin@ file to the amount you dynamically allocate at run--- time to get the correct shared memory usage.------ /Notes About Occupancy/------ Higher occupancy does not necessarily mean higher performance. If a kernel--- is not bandwidth bound, then increasing occupancy will not necessarily--- increase performance. If a kernel invocation is already running at least one--- thread block per multiprocessor in the GPU, and it is bottlenecked by--- computation and not by global memory accesses, then increasing occupancy may--- have no effect. In fact, making changes just to increase occupancy can have--- other effects, such as additional instructions, spills to local memory (which--- is off chip), divergent branches, etc. As with any optimization, you should--- experiment to see how changes affect the *wall clock time* of the kernel--- execution. For bandwidth bound applications, on the other hand, increasing--- occupancy can help better hide the latency of memory accesses, and therefore--- improve performance.---------------------------------------------------------------------------------------module Foreign.CUDA.Analysis.Occupancy (-- Occupancy(..),- occupancy, optimalBlockSize, optimalBlockSizeOf, maxResidentBlocks,- incPow2, incWarp, decPow2, decWarp--) where--import Data.Ord-import Data.List--import Foreign.CUDA.Analysis.Device----- GPU Occupancy per multiprocessor----data Occupancy = Occupancy- {- activeThreads :: !Int, -- ^ Active threads per multiprocessor- activeThreadBlocks :: !Int, -- ^ Active thread blocks per multiprocessor- activeWarps :: !Int, -- ^ Active warps per multiprocessor- occupancy100 :: !Double -- ^ Occupancy of each multiprocessor (percent)- }- deriving (Eq, Ord, Show)----- |--- Calculate occupancy data for a given GPU and kernel resource usage----{-# INLINEABLE occupancy #-}-occupancy- :: DeviceProperties -- ^ Properties of the card in question- -> Int -- ^ Threads per block- -> Int -- ^ Registers per thread- -> Int -- ^ Shared memory per block (bytes)- -> Occupancy-occupancy !dev !thds !regs !smem- = Occupancy at ab aw oc- where- at = ab * thds- aw = ab * warps- ab = minimum [limitWarpBlock, limitRegMP, limitSMemMP]- oc = 100 * fromIntegral aw / fromIntegral (warpsPerMP gpu)-- regs' = 1 `max` regs- smem' = 1 `max` smem-- ceiling' = ceiling :: Double -> Int- ceilingBy x s = s * ceiling' (fromIntegral x / fromIntegral s)-- -- Physical resources- --- gpu = deviceResources dev-- -- Allocation per thread block- --- warps = ceiling' (fromIntegral thds / fromIntegral (threadsPerWarp gpu))- sharedMem = ceilingBy smem' (sharedMemAllocUnit gpu)- registers = case allocation gpu of- Block -> (warps `ceilingBy` regAllocWarp gpu * regs' * threadsPerWarp gpu) `ceilingBy` regAllocUnit gpu- Warp -> warps * ceilingBy (regs' * threadsPerWarp gpu) (regAllocUnit gpu)-- -- Maximum thread blocks per multiprocessor- --- limitWarpBlock = threadBlocksPerMP gpu `min` (warpsPerMP gpu `div` warps)- limitRegMP = threadBlocksPerMP gpu `min` (regFileSize gpu `div` registers)- limitSMemMP = threadBlocksPerMP gpu `min` (sharedMemPerMP gpu `div` sharedMem)----- |--- Optimise multiprocessor occupancy as a function of thread block size and--- resource usage. This returns the smallest satisfying block size in increments--- of a single warp.----{-# INLINEABLE optimalBlockSize #-}-optimalBlockSize- :: DeviceProperties -- ^ Architecture to optimise for- -> (Int -> Int) -- ^ Register count as a function of thread block size- -> (Int -> Int) -- ^ Shared memory usage (bytes) as a function of thread block size- -> (Int, Occupancy)-optimalBlockSize dev = optimalBlockSizeOf dev (decWarp dev)----- |--- As 'optimalBlockSize', but with a generator that produces the specific thread--- block sizes that should be tested. The generated list can produce values in--- any order, but the last satisfying block size will be returned. Hence, values--- should be monotonically decreasing to return the smallest block size yielding--- maximum occupancy, and vice-versa.----{-# INLINEABLE optimalBlockSizeOf #-}-optimalBlockSizeOf- :: DeviceProperties -- ^ Architecture to optimise for- -> [Int] -- ^ Thread block sizes to consider- -> (Int -> Int) -- ^ Register count as a function of thread block size- -> (Int -> Int) -- ^ Shared memory usage (bytes) as a function of thread block size- -> (Int, Occupancy)-optimalBlockSizeOf !dev !threads !freg !fsmem- = maximumBy (comparing (occupancy100 . snd))- $ [ (t, occupancy dev t (freg t) (fsmem t)) | t <- threads ]----- | Increments in powers-of-two, over the range of supported thread block sizes--- for the given device.----{-# INLINEABLE incPow2 #-}-incPow2 :: DeviceProperties -> [Int]-incPow2 !dev = map ((2::Int)^) [lb, lb+1 .. ub]- where- round' = round :: Double -> Int- lb = round' . logBase 2 . fromIntegral $ warpSize dev- ub = round' . logBase 2 . fromIntegral $ maxThreadsPerBlock dev---- | Decrements in powers-of-two, over the range of supported thread block sizes--- for the given device.----{-# INLINEABLE decPow2 #-}-decPow2 :: DeviceProperties -> [Int]-decPow2 !dev = map ((2::Int)^) [ub, ub-1 .. lb]- where- round' = round :: Double -> Int- lb = round' . logBase 2 . fromIntegral $ warpSize dev- ub = round' . logBase 2 . fromIntegral $ maxThreadsPerBlock dev---- | Decrements in the warp size of the device, over the range of supported--- thread block sizes.----{-# INLINEABLE decWarp #-}-decWarp :: DeviceProperties -> [Int]-decWarp !dev = [block, block-warp .. warp]- where- !warp = warpSize dev- !block = maxThreadsPerBlock dev---- | Increments in the warp size of the device, over the range of supported--- thread block sizes.----{-# INLINEABLE incWarp #-}-incWarp :: DeviceProperties -> [Int]-incWarp !dev = [warp, 2*warp .. block]- where- warp = warpSize dev- block = maxThreadsPerBlock dev----- |--- Determine the maximum number of CTAs that can be run simultaneously for a--- given kernel / device combination.----{-# INLINEABLE maxResidentBlocks #-}-maxResidentBlocks- :: DeviceProperties -- ^ Properties of the card in question- -> Int -- ^ Threads per block- -> Int -- ^ Registers per thread- -> Int -- ^ Shared memory per block (bytes)- -> Int -- ^ Maximum number of resident blocks-maxResidentBlocks !dev !thds !regs !smem =- multiProcessorCount dev * activeThreadBlocks (occupancy dev thds regs smem)-
− Foreign/CUDA/Driver.hs
@@ -1,238 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ This module defines an interface to the CUDA driver API. The Driver API--- is a lower-level interface to CUDA devices than that provided by the--- Runtime API. Using the Driver API, the programmer must deal explicitly--- with operations such as initialisation, context management, and loading--- (kernel) modules. Although more difficult to use initially, the Driver--- API provides more control over how CUDA is used. Furthermore, since it--- does not require compiling and linking the program with 'nvcc', the--- Driver API provides better inter-language compatibility.- ----- The following is a short tutorial on using the Driver API. The steps can--- be copied into a file, or run directly in `ghci`, in which case `ghci`--- should be launched with the option `-fno-ghci-sandbox`. This is because--- CUDA maintains CPU-local state, so operations should always be run from--- a bound thread.--------- [/Using the Driver API/]------ Before any operation can be performed, the Driver API must be--- initialised:------ >>> import Foreign.CUDA.Driver--- >>> initialise []------ Next, we must select a GPU that we will execute operations on. Each GPU--- is assigned a unique identifier (beginning at zero). We can get a handle--- to a compute device at a given ordinal using the 'device' operation.--- Given a device handle, we can query the properties of that device using--- 'props'. The number of available CUDA-capable devices is given via--- 'count'. For example:------ >>> count--- 1--- >>> dev0 <- device 0--- >>> props dev0--- DeviceProperties {deviceName = "GeForce GT 650M", computeCapability = 3.0, ...}------ This package also includes the executable 'nvidia-device-query', which when--- executed displays the key properties of all available devices. See--- "Foreign.CUDA.Driver.Device" for additional operations to query the--- capabilities or status of a device.------ Once you have chosen a device to use, the next step is to create a CUDA--- context. A context is associated with a particular device, and all--- operations, such as memory allocation and kernel execution, take place--- with respect to that context. For example, to 'create' a new execution--- context on CUDA device 0:------ >>> ctx <- create dev0 []------ The second argument is a set of 'ContextFlag's which control how the--- context behaves in various situations, for example, whether or not the--- CPU should actively spin when waiting for results from the GPU--- ('SchedSpin'), or to yield control to other threads instead--- ('SchedYield').------ The newly created context is now the /active/ context, and all--- subsequent operations take place within that context. More than one--- context can be created per device, but resources, such as memory--- allocated in the GPU, are unique to each context. The module--- "Foreign.CUDA.Driver.Context" contains operations for managing multiple--- contexts. Some devices allow data to be shared between contexts without--- copying, see "Foreign.CUDA.Driver.Context.Peer" for more information.------ Once the context is no longer needed, it should be 'destroy'ed in order--- to free up any resources that were allocated to it.------ >>> destroy ctx------ Each device also has a unique context which is used by the Runtime API.--- This context can be accessed with the module--- "Foreign.CUDA.Driver.Context.Primary".--------- [/Executing kernels onto the GPU/]------ Once the Driver API is initialised and an execution context is created--- on the GPU, we can begin to interact with it.------ At an example, we'll step through executing the CUDA equivalent of the--- following Haskell function, which element-wise adds the elements of two--- arrays:------ >>> vecAdd xs ys = zipWith (+) xs ys------ The following CUDA kernel can be used to implement this on the GPU:------ > extern "C" __global__ void vecAdd(float *xs, float *ys, float *zs, int N)--- > {--- > int ix = blockIdx.x * blockDim.x + threadIdx.x;--- >--- > if ( ix < N ) {--- > zs[ix] = xs[ix] + ys[ix];--- > }--- > }------ Here, the `__global__` keyword marks the function as a kernel that--- should be computed on the GPU in data parallel. When we execute this--- function on the GPU, (at least) /N/ threads will execute /N/ individual--- instances of the kernel function `vecAdd`. Each thread will operate on--- a single element of each input array to create a single value in the--- result. See the CUDA programming guide for more details.------ We can save this to a file `vector_add.cu`, and compile it using `nvcc`--- into a form that we can then load onto the GPU and execute:------ > $ nvcc --ptx vector_add.cu------ The module "Foreign.CUDA.Driver.Module" contains functions for loading--- the resulting .ptx file (or .cubin files) into the running program.------ >>> mdl <- loadFile "vector_add.ptx"------ Once finished with the module, it is also a good idea to 'unload' it.------ Modules may export kernel functions, global variables, and texture--- references. Before we can execute our function, we need to look it up in--- the module by name.------ >>> vecAdd <- getFun mdl "vecAdd"------ Given this reference to our kernel function, we are almost ready to--- execute it on the device using 'launchKernel', but first, we must create--- some data that we can execute the function on.--------- [/Transferring data to and from the GPU/]------ GPUs typically have their own memory which is separate from the CPU's--- memory, and we need to explicitly copy data back and forth between these--- two regions. The module "Foreign.CUDA.Driver.Marshal" provides functions--- for allocating memory on the GPU, and copying data between the CPU and--- GPU, as well as directly between multiple GPUs.------ For simplicity, we'll use standard Haskell lists for our input and--- output data structure. Note however that this will have significantly--- lower effective bandwidth than reading a single contiguous region of--- memory, so for most practical purposes you will want to use some kind of--- unboxed array.------ >>> let xs = [1..1024] :: [Float]--- >>> let ys = [2,4..2048] :: [Float]------ In CUDA, like C, all memory management is explicit, and arrays on the--- device must be explicitly allocated and freed. As mentioned previously,--- data transfer is also explicit. However, we do provide convenience--- functions for combined allocation and marshalling, as well as bracketed--- operations.------ >>> xs_dev <- newListArray xs--- >>> ys_dev <- newListArray ys--- >>> zs_dev <- mallocArray 1024 :: IO (DevicePtr Float)------ After executing the kernel (see next section), we transfer the result--- back to the host, and free the memory that was allocated on the GPU.------ >>> zs <- peekListArray 1024 zs_dev--- >>> free xs_dev--- >>> free ys_dev--- >>> free zs_dev--------- [/Piecing it all together/]------ Finally, we have everything in place to execute our operation on the--- GPU. Launching a kernel on the GPU consists of creating many threads on--- the GPU which all execute the same function, and each thread has--- a unique identifier in the grid/block hierarchy which can be used to--- identify exactly which element this thread should process (the--- `blockIdx` and `threadIdx` parameters that we saw earlier,--- respectively).------ To execute our function, we will use a grid of 4 blocks, each containing--- 256 threads. Thus, a total of 1024 threads will be launched, which will--- each compute a single element of the output array (recall that our input--- arrays each have 1024 elements). The module--- "Foreign.CUDA.Analysis.Occupancy" contains functions to help determine--- the ideal thread block size for a given kernel and GPU combination.------ >>> launchKernel vecAdd (4,1,1) (256,1,1) 0 Nothing [VArg xs_dev, VArg ys_dev, VArg zs_dev, IArg 1024]------ Note that kernel execution is asynchronous, so we should also wait for--- the operation to complete before attempting to read the results back.------ >>> sync------ And that's it!--------- [/Next steps/]------ As mentioned at the end of the previous section, kernels on the GPU are--- executed asynchronously with respect to the host, and other operations--- such as data transfers can also be executed asynchronously. This allows--- the CPU to continue doing other work while the GPU is busy.--- 'Foreign.CUDA.Driver.Event.Event's can be used to check whether an--- operation has completed yet.------ It is also possible to execute multiple kernels or data transfers--- concurrently with each other, by assigning those operations to different--- execution 'Foreign.CUDA.Driver.Stream.Stream's. Used in conjunction with--- 'Foreign.CUDA.Driver.Event.Event's, operations will be scheduled--- efficiently only once all dependencies (in the form of--- 'Foreign.CUDA.Driver.Event.Event's) have been cleared.------ See "Foreign.CUDA.Driver.Event" and "Foreign.CUDA.Driver.Stream" for--- more information on this topic.--------------------------------------------------------------------------------------module Foreign.CUDA.Driver (-- module Foreign.CUDA.Ptr,- module Foreign.CUDA.Driver.Context,- module Foreign.CUDA.Driver.Device,- module Foreign.CUDA.Driver.Error,- module Foreign.CUDA.Driver.Exec,- module Foreign.CUDA.Driver.Marshal,- module Foreign.CUDA.Driver.Module,- module Foreign.CUDA.Driver.Utils--) where--import Foreign.CUDA.Ptr-import Foreign.CUDA.Driver.Context hiding ( useContext, device )-import Foreign.CUDA.Driver.Device hiding ( useDevice )-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Exec-import Foreign.CUDA.Driver.Marshal hiding ( useDeviceHandle, peekDeviceHandle )-import Foreign.CUDA.Driver.Module-import Foreign.CUDA.Driver.Utils-
− Foreign/CUDA/Driver/Context.hs
@@ -1,23 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Context--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ Context management for low-level driver interface---------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Context (-- module Foreign.CUDA.Driver.Context.Base,- module Foreign.CUDA.Driver.Context.Config,- module Foreign.CUDA.Driver.Context.Peer,--) where--import Foreign.CUDA.Driver.Context.Base-import Foreign.CUDA.Driver.Context.Config-import Foreign.CUDA.Driver.Context.Peer-
− Foreign/CUDA/Driver/Context/Base.chs
@@ -1,241 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Context.Base--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ Context management for the low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Context.Base (-- -- * Context Management- Context(..), ContextFlag(..),- create, destroy, device, pop, push, sync, get, set,-- -- Deprecated in CUDA-4.0- attach, detach,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Device ( Device(..) )-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad ( liftM )-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A device context----newtype Context = Context { useContext :: {# type CUcontext #}}- deriving (Eq, Show)----- |--- Context creation flags----{# enum CUctx_flags as ContextFlag- { underscoreToCase }- with prefix="CU_CTX" deriving (Eq, Show, Bounded) #}---#if CUDA_VERSION >= 4000-{-# DEPRECATED attach, detach "as of CUDA-4.0" #-}-{-# DEPRECATED BlockingSync "use SchedBlockingSync instead" #-}-#endif-------------------------------------------------------------------------------------- Context management------------------------------------------------------------------------------------- |--- Create a new CUDA context and associate it with the calling thread. The--- context is created with a usage count of one, and the caller of 'create'--- must call 'destroy' when done using the context. If a context is already--- current to the thread, it is supplanted by the newly created context and--- must be restored by a subsequent call to 'pop'.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g65dc0012348bc84810e2103a40d8e2cf>----{-# INLINEABLE create #-}-create :: Device -> [ContextFlag] -> IO Context-create !dev !flags = resultIfOk =<< cuCtxCreate flags dev--{-# INLINE cuCtxCreate #-}-{# fun unsafe cuCtxCreate- { alloca- `Context' peekCtx*- , combineBitMasks `[ContextFlag]'- , useDevice `Device' } -> `Status' cToEnum #}- where peekCtx = liftM Context . peek----- |--- Increments the usage count of the context. API: no context flags are--- currently supported, so this parameter must be empty.----{-# INLINEABLE attach #-}-attach :: Context -> [ContextFlag] -> IO ()-attach !ctx !flags = nothingIfOk =<< cuCtxAttach ctx flags--{-# INLINE cuCtxAttach #-}-{# fun unsafe cuCtxAttach- { withCtx* `Context'- , combineBitMasks `[ContextFlag]' } -> `Status' cToEnum #}- where withCtx = with . useContext----- |--- Detach the context, and destroy if no longer used----{-# INLINEABLE detach #-}-detach :: Context -> IO ()-detach !ctx = nothingIfOk =<< cuCtxDetach ctx--{-# INLINE cuCtxDetach #-}-{# fun unsafe cuCtxDetach- { useContext `Context' } -> `Status' cToEnum #}----- |--- Destroy the specified context, regardless of how many threads it is--- current to. The context will be 'pop'ed from the current thread's--- context stack, but if it is current on any other threads it will remain--- current to those threads, and attempts to access it will result in an--- error.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g27a365aebb0eb548166309f58a1e8b8e>----{-# INLINEABLE destroy #-}-destroy :: Context -> IO ()-destroy !ctx = nothingIfOk =<< cuCtxDestroy ctx--{-# INLINE cuCtxDestroy #-}-{# fun unsafe cuCtxDestroy- { useContext `Context' } -> `Status' cToEnum #}----- |--- Return the context bound to the calling CPU thread.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g8f13165846b73750693640fb3e8380d0>----{-# INLINEABLE get #-}-get :: IO (Maybe Context)-#if CUDA_VERSION < 4000-get = requireSDK 'get 4.0-#else-get = resultIfOk =<< cuCtxGetCurrent--{-# INLINE cuCtxGetCurrent #-}-{# fun unsafe cuCtxGetCurrent- { alloca- `Maybe Context' peekCtx* } -> `Status' cToEnum #}- where peekCtx = liftM (nothingIfNull Context) . peek-#endif----- |--- Bind the specified context to the calling thread.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gbe562ee6258b4fcc272ca6478ca2a2f7>----{-# INLINEABLE set #-}-set :: Context -> IO ()-#if CUDA_VERSION < 4000-set _ = requireSDK 'set 4.0-#else-set !ctx = nothingIfOk =<< cuCtxSetCurrent ctx--{-# INLINE cuCtxSetCurrent #-}-{# fun unsafe cuCtxSetCurrent- { useContext `Context' } -> `Status' cToEnum #}-#endif----- |--- Return the device of the currently active context------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g4e84b109eba36cdaaade167f34ae881e>----{-# INLINEABLE device #-}-device :: IO Device-device = resultIfOk =<< cuCtxGetDevice--{-# INLINE cuCtxGetDevice #-}-{# fun unsafe cuCtxGetDevice- { alloca- `Device' dev* } -> `Status' cToEnum #}- where dev = liftM Device . peekIntConv----- |--- Pop the current CUDA context from the CPU thread. The context may then--- be attached to a different CPU thread by calling 'push'.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g2fac188026a062d92e91a8687d0a7902>----{-# INLINEABLE pop #-}-pop :: IO Context-pop = resultIfOk =<< cuCtxPopCurrent--{-# INLINE cuCtxPopCurrent #-}-{# fun unsafe cuCtxPopCurrent- { alloca- `Context' peekCtx* } -> `Status' cToEnum #}- where peekCtx = liftM Context . peek----- |--- Push the given context onto the CPU's thread stack of current contexts.--- The specified context becomes the CPU thread's current context, so all--- operations that operate on the current context are affected.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gb02d4c850eb16f861fe5a29682cc90ba>----{-# INLINEABLE push #-}-push :: Context -> IO ()-push !ctx = nothingIfOk =<< cuCtxPushCurrent ctx--{-# INLINE cuCtxPushCurrent #-}-{# fun unsafe cuCtxPushCurrent- { useContext `Context' } -> `Status' cToEnum #}----- |--- Block until the device has completed all preceding requests. If the--- context was created with the 'SchedBlockingSync' flag, the CPU thread--- will block until the GPU has finished its work.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g7a54725f28d34b8c6299f0c6ca579616>----{-# INLINEABLE sync #-}-sync :: IO ()-sync = nothingIfOk =<< cuCtxSynchronize--{-# INLINE cuCtxSynchronize #-}-{# fun cuCtxSynchronize- { } -> `Status' cToEnum #}-
− Foreign/CUDA/Driver/Context/Config.chs
@@ -1,297 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Context.Config--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ Context configuration for the low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Context.Config (-- -- * Context configuration- getFlags,-- -- ** Resource limits- Limit(..),- getLimit, setLimit,-- -- ** Cache- Cache(..),- getCache, setCache,-- -- ** Shared memory- SharedMem(..),- getSharedMem, setSharedMem,-- -- ** Streams- StreamPriority,- getStreamPriorityRange,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Context.Base-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS-import Foreign.CUDA.Types---- System-import Control.Monad-import Foreign-import Foreign.C-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- Device limits flags----#if CUDA_VERSION < 3010-data Limit-#else-{# enum CUlimit_enum as Limit- { underscoreToCase }- with prefix="CU_LIMIT" deriving (Eq, Show) #}-#endif----- |--- Device cache configuration preference----#if CUDA_VERSION < 3020-data Cache-#else-{# enum CUfunc_cache_enum as Cache- { underscoreToCase }- with prefix="CU_FUNC_CACHE" deriving (Eq, Show) #}-#endif----- |--- Device shared memory configuration preference----#if CUDA_VERSION < 4020-data SharedMem-#else-{# enum CUsharedconfig as SharedMem- { underscoreToCase }- with prefix="CU_SHARED_MEM_CONFIG" deriving (Eq, Show) #}-#endif-------------------------------------------------------------------------------------- Context configuration------------------------------------------------------------------------------------- |--- Return the flags that were used to create the current context.------ Requires CUDA-7.0------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gf81eef983c1e3b2ef4f166d7a930c86d>----{-# INLINEABLE getFlags #-}-getFlags :: IO [ContextFlag]-#if CUDA_VERSION < 7000-getFlags = requireSDK 'getFlags 7.0-#else-getFlags = resultIfOk =<< cuCtxGetFlags--{-# INLINE cuCtxGetFlags #-}-{# fun unsafe cuCtxGetFlags- { alloca- `[ContextFlag]' peekFlags* } -> `Status' cToEnum #}- where- peekFlags = liftM extractBitMasks . peek-#endif----- |--- Query compute 2.0 call stack limits.------ Requires CUDA-3.1.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g9f2d47d1745752aa16da7ed0d111b6a8>----{-# INLINEABLE getLimit #-}-getLimit :: Limit -> IO Int-#if CUDA_VERSION < 3010-getLimit _ = requireSDK 'getLimit 3.1-#else-getLimit !l = resultIfOk =<< cuCtxGetLimit l--{-# INLINE cuCtxGetLimit #-}-{# fun unsafe cuCtxGetLimit- { alloca- `Int' peekIntConv*- , cFromEnum `Limit' } -> `Status' cToEnum #}-#endif----- |--- Specify the size of the call stack, for compute 2.0 devices.------ Requires CUDA-3.1.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g0651954dfb9788173e60a9af7201e65a>----{-# INLINEABLE setLimit #-}-setLimit :: Limit -> Int -> IO ()-#if CUDA_VERSION < 3010-setLimit _ _ = requireSDK 'setLimit 3.1-#else-setLimit !l !n = nothingIfOk =<< cuCtxSetLimit l n--{-# INLINE cuCtxSetLimit #-}-{# fun unsafe cuCtxSetLimit- { cFromEnum `Limit'- , cIntConv `Int' } -> `Status' cToEnum #}-#endif----- |--- On devices where the L1 cache and shared memory use the same hardware--- resources, this function returns the preferred cache configuration for--- the current context.------ Requires CUDA-3.2.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g40b6b141698f76744dea6e39b9a25360>----{-# INLINEABLE getCache #-}-getCache :: IO Cache-#if CUDA_VERSION < 3020-getCache = requireSDK 'getCache 3.2-#else-getCache = resultIfOk =<< cuCtxGetCacheConfig--{-# INLINE cuCtxGetCacheConfig #-}-{# fun unsafe cuCtxGetCacheConfig- { alloca- `Cache' peekEnum* } -> `Status' cToEnum #}-#endif----- |--- On devices where the L1 cache and shared memory use the same hardware--- resources, this sets the preferred cache configuration for the current--- context. This is only a preference.------ Any function configuration set via--- 'Foreign.CUDA.Driver.Exec.setCacheConfigFun' will be preferred over this--- context-wide setting.------ Requires CUDA-3.2.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g54699acf7e2ef27279d013ca2095f4a3>----{-# INLINEABLE setCache #-}-setCache :: Cache -> IO ()-#if CUDA_VERSION < 3020-setCache _ = requireSDK 'setCache 3.2-#else-setCache !c = nothingIfOk =<< cuCtxSetCacheConfig c--{-# INLINE cuCtxSetCacheConfig #-}-{# fun unsafe cuCtxSetCacheConfig- { cFromEnum `Cache' } -> `Status' cToEnum #}-#endif----- |--- Return the current size of the shared memory banks in the current--- context. On devices with configurable shared memory banks,--- 'setSharedMem' can be used to change the configuration, so that--- subsequent kernel launches will by default us the new bank size. On--- devices without configurable shared memory, this function returns the--- fixed bank size of the hardware.------ Requires CUDA-4.2------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g17153a1b8b8c756f7ab8505686a4ad74>----{-# INLINEABLE getSharedMem #-}-getSharedMem :: IO SharedMem-#if CUDA_VERSION < 4020-getSharedMem = requireSDK 'getSharedMem 4.2-#else-getSharedMem = resultIfOk =<< cuCtxGetSharedMemConfig--{-# INLINE cuCtxGetSharedMemConfig #-}-{# fun unsafe cuCtxGetSharedMemConfig- { alloca- `SharedMem' peekEnum*- } -> `Status' cToEnum #}-#endif----- |--- On devices with configurable shared memory banks, this function will set--- the context's shared memory bank size that will be used by default for--- subsequent kernel launches.------ Changing the shared memory configuration between launches may insert--- a device synchronisation.------ Shared memory bank size does not affect shared memory usage or kernel--- occupancy, but may have major effects on performance. Larger bank sizes--- allow for greater potential bandwidth to shared memory, but change the--- kinds of accesses which result in bank conflicts.------ Requires CUDA-4.2------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g2574235fa643f8f251bf7bc28fac3692>----{-# INLINEABLE setSharedMem #-}-setSharedMem :: SharedMem -> IO ()-#if CUDA_VERSION < 4020-setSharedMem _ = requireSDK 'setSharedMem 4.2-#else-setSharedMem !c = nothingIfOk =<< cuCtxSetSharedMemConfig c--{-# INLINE cuCtxSetSharedMemConfig #-}-{# fun unsafe cuCtxSetSharedMemConfig- { cFromEnum `SharedMem' } -> `Status' cToEnum #}-#endif------ |--- Returns the numerical values that correspond to the greatest and least--- priority execution streams in the current context respectively. Stream--- priorities follow the convention that lower numerical numbers correspond--- to higher priorities. The range of meaningful stream priorities is given--- by the inclusive range [greatestPriority,leastPriority].------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g137920ab61a71be6ce67605b9f294091>----{-# INLINEABLE getStreamPriorityRange #-}-getStreamPriorityRange :: IO (StreamPriority, StreamPriority)-#if CUDA_VERSION < 5050-getStreamPriorityRange = requireSDK 'getStreamPriorityRange 5.5-#else-getStreamPriorityRange = do- (r,l,h) <- cuCtxGetStreamPriorityRange- resultIfOk (r, (h,l))--{-# INLINE cuCtxGetStreamPriorityRange #-}-{# fun unsafe cuCtxGetStreamPriorityRange- { alloca- `Int' peekIntConv*- , alloca- `Int' peekIntConv*- }- -> `Status' cToEnum #}-#endif-
− Foreign/CUDA/Driver/Context/Peer.chs
@@ -1,131 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Context.Peer--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ Direct peer context access functions for the low-level driver interface.------ Since: CUDA-4.0--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Context.Peer (-- -- * Peer Access- PeerFlag,- accessible, add, remove,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Context.Base ( Context(..) )-import Foreign.CUDA.Driver.Device ( Device(..) )-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- Possible option values for direct peer memory access----data PeerFlag-instance Enum PeerFlag where-#ifdef USE_EMPTY_CASE- toEnum x = case x of {}- fromEnum x = case x of {}-#endif-------------------------------------------------------------------------------------- Peer access------------------------------------------------------------------------------------- |--- Queries if the first device can directly access the memory of the second. If--- direct access is possible, it can then be enabled with 'add'.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g496bdaae1f632ebfb695b99d2c40f19e>----{-# INLINEABLE accessible #-}-accessible :: Device -> Device -> IO Bool-#if CUDA_VERSION < 4000-accessible _ _ = requireSDK 'accessible 4.0-#else-accessible !dev !peer = resultIfOk =<< cuDeviceCanAccessPeer dev peer--{-# INLINE cuDeviceCanAccessPeer #-}-{# fun unsafe cuDeviceCanAccessPeer- { alloca- `Bool' peekBool*- , useDevice `Device'- , useDevice `Device' } -> `Status' cToEnum #}-#endif----- |--- If the devices of both the current and supplied contexts support unified--- addressing, then enable allocations in the supplied context to be accessible--- by the current context.------ Note that access is unidirectional, and in order to access memory in the--- current context from the peer context, a separate symmetric call to--- 'add' is required.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g0889ec6728e61c05ed359551d67b3f5a>----{-# INLINEABLE add #-}-add :: Context -> [PeerFlag] -> IO ()-#if CUDA_VERSION < 4000-add _ _ = requireSDK 'add 4.0-#else-add !ctx !flags = nothingIfOk =<< cuCtxEnablePeerAccess ctx flags--{-# INLINE cuCtxEnablePeerAccess #-}-{# fun unsafe cuCtxEnablePeerAccess- { useContext `Context'- , combineBitMasks `[PeerFlag]' } -> `Status' cToEnum #}-#endif----- |--- Disable direct memory access from the current context to the supplied--- peer context, and unregisters any registered allocations.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g5b4b6936ea868d4954ce4d841a3b4810>----{-# INLINEABLE remove #-}-remove :: Context -> IO ()-#if CUDA_VERSION < 4000-remove _ = requireSDK 'remave 4.0-#else-remove !ctx = nothingIfOk =<< cuCtxDisablePeerAccess ctx--{-# INLINE cuCtxDisablePeerAccess #-}-{# fun unsafe cuCtxDisablePeerAccess- { useContext `Context' } -> `Status' cToEnum #}-#endif-
− Foreign/CUDA/Driver/Context/Primary.chs
@@ -1,170 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Context.Primary--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Primary context management for low-level driver interface. The primary--- context is unique per device and shared with the Runtime API. This--- allows integration with other libraries using CUDA.------ Since: CUDA-7.0--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Context.Primary (-- status, setup, reset, retain, release,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Context.Base-import Foreign.CUDA.Driver.Device-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Control.Exception-import Control.Monad-import Foreign-import Foreign.C-------------------------------------------------------------------------------------- Primary context management-------------------------------------------------------------------------------------- |--- Get the status of the primary context. Returns whether the current--- context is active, and the flags it was (or will be) created with.------ Requires CUDA-7.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g65f3e018721b6d90aa05cfb56250f469>----{-# INLINEABLE status #-}-status :: Device -> IO (Bool, [ContextFlag])-#if CUDA_VERSION < 7000-status _ = requireSDK 'status 7.0-#else-status !dev =- cuDevicePrimaryCtxGetState dev >>= \(rv, !flags, !active) ->- case rv of- Success -> return (active, flags)- _ -> throwIO (ExitCode rv)--{# fun unsafe cuDevicePrimaryCtxGetState- { useDevice `Device'- , alloca- `[ContextFlag]' peekFlags*- , alloca- `Bool' peekBool*- } -> `Status' cToEnum #}- where- peekFlags = liftM extractBitMasks . peek-#endif----- |--- Specify the flags that the primary context should be created with. Note--- that this is an error if the primary context is already active.------ Requires CUDA-7.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1gd779a84f17acdad0d9143d9fe719cfdf>----{-# INLINEABLE setup #-}-setup :: Device -> [ContextFlag] -> IO ()-#if CUDA_VERSION < 7000-setup _ _ = requireSDK 'setup 7.0-#else-setup !dev !flags = nothingIfOk =<< cuDevicePrimaryCtxSetFlags dev flags--{-# INLINE cuDevicePrimaryCtxSetFlags #-}-{# fun unsafe cuDevicePrimaryCtxSetFlags- { useDevice `Device'- , combineBitMasks `[ContextFlag]'- } -> `Status' cToEnum #}-#endif----- |--- Destroy all allocations and reset all state on the primary context of--- the given device in the current process. Requires cuda-7.0------ Requires CUDA-7.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g5d38802e8600340283958a117466ce12>----{-# INLINEABLE reset #-}-reset :: Device -> IO ()-#if CUDA_VERSION < 7000-reset _ = requireSDK 'reset 7.0-#else-reset !dev = nothingIfOk =<< cuDevicePrimaryCtxReset dev--{-# INLINE cuDevicePrimaryCtxReset #-}-{# fun unsafe cuDevicePrimaryCtxReset- { useDevice `Device' } -> `Status' cToEnum #}-#endif----- |--- Release the primary context on the given device. If there are no more--- references to the primary context it will be destroyed, regardless of--- how many threads it is current to.------ Unlike 'Foreign.CUDA.Driver.Context.Base.pop' this does not pop the--- context from the stack in any circumstances.------ Requires CUDA-7.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1gf2a8bc16f8df0c88031f6a1ba3d6e8ad>----{-# INLINEABLE release #-}-release :: Device -> IO ()-#if CUDA_VERSION < 7000-release _ = requireSDK 'release 7.0-#else-release !dev = nothingIfOk =<< cuDevicePrimaryCtxRelease dev--{-# INLINE cuDevicePrimaryCtxRelease #-}-{# fun unsafe cuDevicePrimaryCtxRelease- { useDevice `Device' } -> `Status' cToEnum #}-#endif----- |--- Retain the primary context for the given device, creating it if--- necessary, and increasing its usage count. The caller must call--- 'release' when done using the context. Unlike--- 'Foreign.CUDA.Driver.Context.Base.create' the newly retained context is--- not pushed onto the stack.------ Requires CUDA-7.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g9051f2d5c31501997a6cb0530290a300>----{-# INLINEABLE retain #-}-retain :: Device -> IO Context-#if CUDA_VERSION < 7000-retain _ = requireSDK 'retain 7.0-#else-retain !dev = resultIfOk =<< cuDevicePrimaryCtxRetain dev--{-# INLINE cuDevicePrimaryCtxRetain #-}-{# fun unsafe cuDevicePrimaryCtxRetain- { alloca- `Context' peekCtx*- , useDevice `Device'- } -> `Status' cToEnum #}- where- peekCtx = liftM Context . peek-#endif-
− Foreign/CUDA/Driver/Device.chs
@@ -1,403 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Device--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Device management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Device (-- -- * Device Management- Device(..),- DeviceProperties(..), DeviceAttribute(..), Compute(..), ComputeMode(..), InitFlag,- initialise, capability, device, attribute, count, name, props, totalMem--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Analysis.Device-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad ( liftM )-import Control.Applicative-import Prelude-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A CUDA device----newtype Device = Device { useDevice :: {# type CUdevice #}}- deriving (Eq, Show)----- |--- Device attributes----{# enum CUdevice_attribute as DeviceAttribute- { underscoreToCase- , MAX as CU_DEVICE_ATTRIBUTE_MAX } -- ignore- with prefix="CU_DEVICE_ATTRIBUTE" deriving (Eq, Show) #}---#if CUDA_VERSION < 5000-{# pointer *CUdevprop as ^ foreign -> CUDevProp nocode #}------- Properties of the compute device (internal helper).--- Replaced by cuDeviceGetAttribute in CUDA-5.0 and later.----data CUDevProp = CUDevProp- {- cuMaxThreadsPerBlock :: !Int, -- Maximum number of threads per block- cuMaxBlockSize :: !(Int,Int,Int), -- Maximum size of each dimension of a block- cuMaxGridSize :: !(Int,Int,Int), -- Maximum size of each dimension of a grid- cuSharedMemPerBlock :: !Int64, -- Shared memory available per block in bytes- cuTotalConstMem :: !Int64, -- Constant memory available on device in bytes- cuWarpSize :: !Int, -- Warp size in threads (SIMD width)- cuMemPitch :: !Int64, -- Maximum pitch in bytes allowed by memory copies- cuRegsPerBlock :: !Int, -- 32-bit registers available per block- cuClockRate :: !Int, -- Clock frequency in kilohertz- cuTextureAlignment :: !Int64 -- Alignment requirement for textures- }- deriving (Show)---instance Storable CUDevProp where- sizeOf _ = {#sizeof CUdevprop#}- alignment _ = alignment (undefined :: Ptr ())-- poke _ _ = error "no instance for Foreign.Storable.poke DeviceProperties"- peek p = do- tb <- cIntConv `fmap` {#get CUdevprop.maxThreadsPerBlock#} p- sm <- cIntConv `fmap` {#get CUdevprop.sharedMemPerBlock#} p- cm <- cIntConv `fmap` {#get CUdevprop.totalConstantMemory#} p- ws <- cIntConv `fmap` {#get CUdevprop.SIMDWidth#} p- mp <- cIntConv `fmap` {#get CUdevprop.memPitch#} p- rb <- cIntConv `fmap` {#get CUdevprop.regsPerBlock#} p- cl <- cIntConv `fmap` {#get CUdevprop.clockRate#} p- ta <- cIntConv `fmap` {#get CUdevprop.textureAlign#} p-- [t1,t2,t3] <- peekArrayWith cIntConv 3 =<< {#get CUdevprop.maxThreadsDim#} p- [g1,g2,g3] <- peekArrayWith cIntConv 3 =<< {#get CUdevprop.maxGridSize#} p-- return CUDevProp- {- cuMaxThreadsPerBlock = tb,- cuMaxBlockSize = (t1,t2,t3),- cuMaxGridSize = (g1,g2,g3),- cuSharedMemPerBlock = sm,- cuTotalConstMem = cm,- cuWarpSize = ws,- cuMemPitch = mp,- cuRegsPerBlock = rb,- cuClockRate = cl,- cuTextureAlignment = ta- }-#endif----- |--- Possible option flags for CUDA initialisation. Dummy instance until the API--- exports actual option values.----data InitFlag-instance Enum InitFlag where-#ifdef USE_EMPTY_CASE- toEnum x = case x of {}- fromEnum x = case x of {}-#endif-------------------------------------------------------------------------------------- Initialisation------------------------------------------------------------------------------------- |--- Initialise the CUDA driver API. This must be called before any other--- driver function.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__INITIALIZE.html#group__CUDA__INITIALIZE_1g0a2f1517e1bd8502c7194c3a8c134bc3>----{-# INLINEABLE initialise #-}-initialise :: [InitFlag] -> IO ()-initialise !flags = nothingIfOk =<< cuInit flags <* enable_constructors--{-# INLINE enable_constructors #-}-{# fun unsafe enable_constructors { } -> `()' #}--{-# INLINE cuInit #-}-{# fun unsafe cuInit- { combineBitMasks `[InitFlag]' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Device Management------------------------------------------------------------------------------------- |--- Return the compute compatibility revision supported by the device----{-# INLINEABLE capability #-}-capability :: Device -> IO Compute-#if CUDA_VERSION >= 5000-capability !dev =- Compute <$> attribute dev ComputeCapabilityMajor- <*> attribute dev ComputeCapabilityMinor-#else--- Deprecated as of CUDA-5.0----capability !dev =- (\(!s,!a,!b) -> resultIfOk (s,Compute a b)) =<< cuDeviceComputeCapability dev--{-# INLINE cuDeviceComputeCapability #-}-{# fun unsafe cuDeviceComputeCapability- { alloca- `Int' peekIntConv*- , alloca- `Int' peekIntConv*- , useDevice `Device' } -> `Status' cToEnum #}-#endif----- |--- Return a handle to the compute device at the given ordinal.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g8bdd1cc7201304b01357b8034f6587cb>----{-# INLINEABLE device #-}-device :: Int -> IO Device-device !d = resultIfOk =<< cuDeviceGet d--{-# INLINE cuDeviceGet #-}-{# fun unsafe cuDeviceGet- { alloca- `Device' dev*- , cIntConv `Int' } -> `Status' cToEnum #}- where dev = liftM Device . peek----- |--- Return the selected attribute for the given device.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g9c3e1414f0ad901d3278a4d6645fc266>----{-# INLINEABLE attribute #-}-attribute :: Device -> DeviceAttribute -> IO Int-attribute !d !a = resultIfOk =<< cuDeviceGetAttribute a d--{-# INLINE cuDeviceGetAttribute #-}-{# fun unsafe cuDeviceGetAttribute- { alloca- `Int' peekIntConv*- , cFromEnum `DeviceAttribute'- , useDevice `Device' } -> `Status' cToEnum #}----- |--- Return the number of device with compute capability > 1.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g52b5ce05cb8c5fb6831b2c0ff2887c74>----{-# INLINEABLE count #-}-count :: IO Int-count = resultIfOk =<< cuDeviceGetCount--{-# INLINE cuDeviceGetCount #-}-{# fun unsafe cuDeviceGetCount- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}----- |--- The identifying name of the device.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1gef75aa30df95446a845f2a7b9fffbb7f>----{-# INLINEABLE name #-}-name :: Device -> IO String-name !d = resultIfOk =<< cuDeviceGetName d--{-# INLINE cuDeviceGetName #-}-{# fun unsafe cuDeviceGetName- { allocaS- `String'& peekS*- , useDevice `Device' } -> `Status' cToEnum #}- where- len = 512- allocaS a = allocaBytes len $ \p -> a (p, cIntConv len)- peekS s _ = peekCString s----- |--- Return the properties of the selected device----{-# INLINEABLE props #-}-props :: Device -> IO DeviceProperties-props !d = do--#if CUDA_VERSION < 5000- -- Old versions of the CUDA API used the separate cuDeviceGetProperties- -- function to probe some properties, and cuDeviceGetAttribute for- -- others. As of CUDA-5.0, the former was deprecated and its- -- functionality subsumed by the latter, which we use below.- --- p <- resultIfOk =<< cuDeviceGetProperties d- let cm = cuTotalConstMem p- sm = cuSharedMemPerBlock p- rb = cuRegsPerBlock p- ws = cuWarpSize p- tb = cuMaxThreadsPerBlock p- bs = cuMaxBlockSize p- gs = cuMaxGridSize p- cl = cuClockRate p- mp = cuMemPitch p- ta = cuTextureAlignment p-#else- cm <- fromIntegral <$> attribute d TotalConstantMemory- sm <- fromIntegral <$> attribute d SharedMemoryPerBlock- mp <- fromIntegral <$> attribute d MaxPitch- ta <- fromIntegral <$> attribute d TextureAlignment- cl <- attribute d ClockRate- ws <- attribute d WarpSize- rb <- attribute d RegistersPerBlock- tb <- attribute d MaxThreadsPerBlock- bs <- (,,) <$> attribute d MaxBlockDimX- <*> attribute d MaxBlockDimY- <*> attribute d MaxBlockDimZ- gs <- (,,) <$> attribute d MaxGridDimX- <*> attribute d MaxGridDimY- <*> attribute d MaxGridDimZ-#endif-- -- The rest of the properties.- --- n <- name d- cc <- capability d- gm <- totalMem d- pc <- attribute d MultiprocessorCount- md <- toEnum `fmap` attribute d ComputeMode- ov <- toBool `fmap` attribute d GpuOverlap- ke <- toBool `fmap` attribute d KernelExecTimeout- tg <- toBool `fmap` attribute d Integrated- hm <- toBool `fmap` attribute d CanMapHostMemory-#if CUDA_VERSION >= 3000- ck <- toBool `fmap` attribute d ConcurrentKernels- ee <- toBool `fmap` attribute d EccEnabled- u1 <- attribute d MaximumTexture1dWidth- u21 <- attribute d MaximumTexture2dWidth- u22 <- attribute d MaximumTexture2dHeight- u31 <- attribute d MaximumTexture3dWidth- u32 <- attribute d MaximumTexture3dHeight- u33 <- attribute d MaximumTexture3dDepth-#endif-#if CUDA_VERSION >= 4000- ae <- attribute d AsyncEngineCount- l2 <- attribute d L2CacheSize- tm <- attribute d MaxThreadsPerMultiprocessor- mw <- attribute d GlobalMemoryBusWidth- mc <- attribute d MemoryClockRate- pb <- attribute d PciBusId- pd <- attribute d PciDeviceId- pm <- attribute d PciDomainId- ua <- toBool `fmap` attribute d UnifiedAddressing- tcc <- toBool `fmap` attribute d TccDriver-#endif-#if CUDA_VERSION >= 5050- sp <- toBool `fmap` attribute d StreamPrioritiesSupported-#endif-#if CUDA_VERSION >= 6000- gl1 <- toBool `fmap` attribute d GlobalL1CacheSupported- ll1 <- toBool `fmap` attribute d LocalL1CacheSupported- mm <- toBool `fmap` attribute d ManagedMemory- mg <- toBool `fmap` attribute d MultiGpuBoard- mid <- attribute d MultiGpuBoardGroupId-#endif-- return DeviceProperties- {- deviceName = n- , computeCapability = cc- , totalGlobalMem = gm- , totalConstMem = cm- , sharedMemPerBlock = sm- , regsPerBlock = rb- , warpSize = ws- , maxThreadsPerBlock = tb- , maxBlockSize = bs- , maxGridSize = gs- , clockRate = cl- , multiProcessorCount = pc- , memPitch = mp- , textureAlignment = ta- , computeMode = md- , deviceOverlap = ov- , kernelExecTimeoutEnabled = ke- , integrated = tg- , canMapHostMemory = hm-#if CUDA_VERSION >= 3000- , concurrentKernels = ck- , eccEnabled = ee- , maxTextureDim1D = u1- , maxTextureDim2D = (u21,u22)- , maxTextureDim3D = (u31,u32,u33)-#endif-#if CUDA_VERSION >= 4000- , asyncEngineCount = ae- , cacheMemL2 = l2- , maxThreadsPerMultiProcessor = tm- , memBusWidth = mw- , memClockRate = mc- , pciInfo = PCI pb pd pm- , tccDriverEnabled = tcc- , unifiedAddressing = ua-#endif-#if CUDA_VERSION >= 5050- , streamPriorities = sp-#endif-#if CUDA_VERSION >= 6000- , globalL1Cache = gl1- , localL1Cache = ll1- , managedMemory = mm- , multiGPUBoard = mg- , multiGPUBoardGroupID = mid-#endif- }--#if CUDA_VERSION < 5000--- Deprecated as of CUDA-5.0-{-# INLINE cuDeviceGetProperties #-}-{# fun unsafe cuDeviceGetProperties- { alloca- `CUDevProp' peek*- , useDevice `Device' } -> `Status' cToEnum #}-#endif----- |--- The total memory available on the device (bytes).------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1gc6a0d6551335a3780f9f3c967a0fde5d>----{-# INLINEABLE totalMem #-}-totalMem :: Device -> IO Int64-totalMem !d = resultIfOk =<< cuDeviceTotalMem d--{-# INLINE cuDeviceTotalMem #-}-{# fun unsafe cuDeviceTotalMem- { alloca- `Int64' peekIntConv*- , useDevice `Device' } -> `Status' cToEnum #}-
− Foreign/CUDA/Driver/Error.chs
@@ -1,210 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Error--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Error handling--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Error (-- -- * CUDA Errors- Status(..), CUDAException(..),- describe,- cudaError, cudaErrorIO, requireSDK,- resultIfOk, nothingIfOk,--) where---- Friends-import Foreign.CUDA.Internal.C2HS---- System-import Control.Exception-import Control.Monad-import Data.Typeable-import Foreign.C-import Foreign.Marshal-import Foreign.Ptr-import Foreign.Storable-import Language.Haskell.TH-import System.IO.Unsafe-import Text.Printf---#include "cbits/stubs.h"-{# context lib="cuda" #}-------------------------------------------------------------------------------------- Return Status---------------------------------------------------------------------------------------- Error Codes----{# enum CUresult as Status- { underscoreToCase- , CUDA_SUCCESS as Success- , CUDA_ERROR_NO_BINARY_FOR_GPU as NoBinaryForGPU- , CUDA_ERROR_INVALID_PTX as InvalidPTX- , CUDA_ERROR_INVALID_PC as InvalidPC- }- with prefix="CUDA_ERROR" deriving (Eq, Show) #}----- |--- Return a descriptive error string associated with a particular error code----describe :: Status -> String-#if CUDA_VERSION >= 6000-describe status- = unsafePerformIO $ resultIfOk =<< cuGetErrorString status--{# fun unsafe cuGetErrorString- { cFromEnum `Status'- , alloca- `String' ppeek* } -> `Status' cToEnum #}- where- ppeek = peek >=> peekCString--#else-describe Success = "no error"-describe InvalidValue = "invalid argument"-describe OutOfMemory = "out of memory"-describe NotInitialized = "driver not initialised"-describe Deinitialized = "driver deinitialised"-describe NoDevice = "no CUDA-capable device is available"-describe InvalidDevice = "invalid device ordinal"-describe InvalidImage = "invalid kernel image"-describe InvalidContext = "invalid context handle"-describe ContextAlreadyCurrent = "context already current"-describe MapFailed = "map failed"-describe UnmapFailed = "unmap failed"-describe ArrayIsMapped = "array is mapped"-describe AlreadyMapped = "already mapped"-describe NoBinaryForGPU = "no binary available for this GPU"-describe AlreadyAcquired = "resource already acquired"-describe NotMapped = "not mapped"-describe InvalidSource = "invalid source"-describe FileNotFound = "file not found"-describe InvalidHandle = "invalid handle"-describe NotFound = "not found"-describe NotReady = "device not ready"-describe LaunchFailed = "unspecified launch failure"-describe LaunchOutOfResources = "too many resources requested for launch"-describe LaunchTimeout = "the launch timed out and was terminated"-describe LaunchIncompatibleTexturing = "launch with incompatible texturing"-#if CUDA_VERSION >= 3000-describe NotMappedAsArray = "mapped resource not available for access as an array"-describe NotMappedAsPointer = "mapped resource not available for access as a pointer"-describe EccUncorrectable = "uncorrectable ECC error detected"-#endif-#if CUDA_VERSION >= 3000 && CUDA_VERSION < 3020-describe PointerIs64bit = "attempt to retrieve a 64-bit pointer via a 32-bit API function"-describe SizeIs64bit = "attempt to retrieve 64-bit size via a 32-bit API function"-#endif-#if CUDA_VERSION >= 3010-describe UnsupportedLimit = "limits not supported by device"-describe SharedObjectSymbolNotFound = "link to a shared object failed to resolve"-describe SharedObjectInitFailed = "shared object initialisation failed"-#endif-#if CUDA_VERSION >= 3020-describe OperatingSystem = "operating system call failed"-#endif-#if CUDA_VERSION >= 4000-describe ProfilerDisabled = "profiling APIs disabled: application running with visual profiler"-describe ProfilerNotInitialized = "profiler not initialised"-describe ProfilerAlreadyStarted = "profiler already started"-describe ProfilerAlreadyStopped = "profiler already stopped"-describe ContextAlreadyInUse = "context is already bound to a thread and in use"-describe PeerAccessAlreadyEnabled = "peer access already enabled"-describe PeerAccessNotEnabled = "peer access has not been enabled"-describe PrimaryContextActive = "primary context for this device has already been initialised"-describe ContextIsDestroyed = "context already destroyed"-#endif-#if CUDA_VERSION >= 4010-describe Assert = "device-side assert triggered"-describe TooManyPeers = "peer mapping resources exhausted"-describe HostMemoryAlreadyRegistered = "part or all of the requested memory range is already mapped"-describe HostMemoryNotRegistered = "pointer does not correspond to a registered memory region"-#endif-#if CUDA_VERSION >= 5000-describe PeerAccessUnsupported = "peer access is not supported across the given devices"-describe NotPermitted = "not permitted"-describe NotSupported = "not supported"-#endif-describe Unknown = "unknown error"-#endif-------------------------------------------------------------------------------------- Exceptions-----------------------------------------------------------------------------------data CUDAException- = ExitCode Status- | UserError String- deriving Typeable--instance Exception CUDAException--instance Show CUDAException where- showsPrec _ (ExitCode s) = showString ("CUDA Exception: " ++ describe s)- showsPrec _ (UserError s) = showString ("CUDA Exception: " ++ s)----- |--- Raise a CUDAException. Exceptions can be thrown from pure code, but can only--- be caught in the 'IO' monad.----{-# RULES "cudaError/IO" cudaError = cudaErrorIO #-}-{-# NOINLINE [1] cudaError #-}-cudaError :: String -> a-cudaError s = throw (UserError s)---- |--- Raise a CUDAException in the IO Monad----cudaErrorIO :: String -> IO a-cudaErrorIO s = throwIO (UserError s)---- |--- A specially formatted error message----requireSDK :: Name -> Double -> a-requireSDK n v = cudaError $ printf "'%s' requires at least cuda-%3.1f\n" (show n) v-------------------------------------------------------------------------------------- Helper Functions-------------------------------------------------------------------------------------- |--- Return the results of a function on successful execution, otherwise throw an--- exception with an error string associated with the return code----{-# INLINE resultIfOk #-}-resultIfOk :: (Status, a) -> IO a-resultIfOk (status, !result) =- case status of- Success -> return result- _ -> throwIO (ExitCode status)----- |--- Throw an exception with an error string associated with an unsuccessful--- return code, otherwise return unit.----{-# INLINE nothingIfOk #-}-nothingIfOk :: Status -> IO ()-nothingIfOk status =- case status of- Success -> return ()- _ -> throwIO (ExitCode status)-
− Foreign/CUDA/Driver/Event.chs
@@ -1,163 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Event--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Event management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Event (-- -- * Event Management- Event(..), EventFlag(..), WaitFlag,- create, destroy, elapsedTime, query, record, wait, block--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Types-import Foreign.CUDA.Internal.C2HS-import Foreign.CUDA.Driver.Error---- System-import Foreign-import Foreign.C-import Data.Maybe-import Control.Monad ( liftM )-import Control.Exception ( throwIO )-------------------------------------------------------------------------------------- Event management------------------------------------------------------------------------------------- |--- Create a new event------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g450687e75f3ff992fe01662a43d9d3db>----{-# INLINEABLE create #-}-create :: [EventFlag] -> IO Event-create !flags = resultIfOk =<< cuEventCreate flags--{-# INLINE cuEventCreate #-}-{# fun unsafe cuEventCreate- { alloca- `Event' peekEvt*- , combineBitMasks `[EventFlag]' } -> `Status' cToEnum #}- where peekEvt = liftM Event . peek----- |--- Destroy an event------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g593ec73a8ec5a5fc031311d3e4dca1ef>----{-# INLINEABLE destroy #-}-destroy :: Event -> IO ()-destroy !ev = nothingIfOk =<< cuEventDestroy ev--{-# INLINE cuEventDestroy #-}-{# fun unsafe cuEventDestroy- { useEvent `Event' } -> `Status' cToEnum #}----- |--- Determine the elapsed time (in milliseconds) between two events------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1gdfb1178807353bbcaa9e245da497cf97>----{-# INLINEABLE elapsedTime #-}-elapsedTime :: Event -> Event -> IO Float-elapsedTime !ev1 !ev2 = resultIfOk =<< cuEventElapsedTime ev1 ev2--{-# INLINE cuEventElapsedTime #-}-{# fun unsafe cuEventElapsedTime- { alloca- `Float' peekFloatConv*- , useEvent `Event'- , useEvent `Event' } -> `Status' cToEnum #}----- |--- Determines if a event has actually been recorded------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g6f0704d755066b0ee705749ae911deef>----{-# INLINEABLE query #-}-query :: Event -> IO Bool-query !ev =- cuEventQuery ev >>= \rv ->- case rv of- Success -> return True- NotReady -> return False- _ -> throwIO (ExitCode rv)--{-# INLINE cuEventQuery #-}-{# fun unsafe cuEventQuery- { useEvent `Event' } -> `Status' cToEnum #}----- |--- Record an event once all operations in the current context (or optionally--- specified stream) have completed. This operation is asynchronous.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g95424d3be52c4eb95d83861b70fb89d1>----{-# INLINEABLE record #-}-record :: Event -> Maybe Stream -> IO ()-record !ev !mst =- nothingIfOk =<< cuEventRecord ev (fromMaybe defaultStream mst)--{-# INLINE cuEventRecord #-}-{# fun unsafe cuEventRecord- { useEvent `Event'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Makes all future work submitted to the (optional) stream wait until the given--- event reports completion before beginning execution. Synchronisation is--- performed on the device, including when the event and stream are from--- different device contexts.------ Requires CUDA-3.2.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g6a898b652dfc6aa1d5c8d97062618b2f>----{-# INLINEABLE wait #-}-wait :: Event -> Maybe Stream -> [WaitFlag] -> IO ()-#if CUDA_VERSION < 3020-wait _ _ _ = requireSDK 'wait 3.2-#else-wait !ev !mst !flags =- nothingIfOk =<< cuStreamWaitEvent (fromMaybe defaultStream mst) ev flags--{-# INLINE cuStreamWaitEvent #-}-{# fun unsafe cuStreamWaitEvent- { useStream `Stream'- , useEvent `Event'- , combineBitMasks `[WaitFlag]' } -> `Status' cToEnum #}-#endif---- |--- Wait until the event has been recorded------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g9e520d34e51af7f5375610bca4add99c>----{-# INLINEABLE block #-}-block :: Event -> IO ()-block !ev = nothingIfOk =<< cuEventSynchronize ev--{-# INLINE cuEventSynchronize #-}-{# fun cuEventSynchronize- { useEvent `Event' } -> `Status' cToEnum #}-
− Foreign/CUDA/Driver/Exec.chs
@@ -1,380 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Exec--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Kernel execution control for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Exec (-- -- * Kernel Execution- Fun(Fun), FunParam(..), FunAttribute(..), SharedMem(..),- requires,- setCacheConfigFun,- setSharedMemConfigFun,- launchKernel, launchKernel',-- -- Deprecated since CUDA-4.0- setBlockShape, setSharedSize, setParams, launch,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Internal.C2HS-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Context ( Cache(..), SharedMem(..) )-import Foreign.CUDA.Driver.Stream ( Stream(..), defaultStream )---- System-import Foreign-import Foreign.C-import Data.Maybe-import Control.Monad ( zipWithM_ )---#if CUDA_VERSION >= 4000-{-# DEPRECATED setBlockShape, setSharedSize, setParams, launch- "use launchKernel instead" #-}-#endif-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A @\_\_global\_\_@ device function----newtype Fun = Fun { useFun :: {# type CUfunction #}}----- |--- Function attributes----{# enum CUfunction_attribute as FunAttribute- { underscoreToCase- , MAX_THREADS_PER_BLOCK as MaxKernelThreadsPerBlock- , MAX as CU_FUNC_ATTRIBUTE_MAX } -- ignore- with prefix="CU_FUNC_ATTRIBUTE" deriving (Eq, Show) #}---- |--- Kernel function parameters----data FunParam where- IArg :: !Int32 -> FunParam- FArg :: !Float -> FunParam- VArg :: Storable a => !a -> FunParam--instance Storable FunParam where- sizeOf (IArg _) = sizeOf (undefined :: CUInt)- sizeOf (FArg _) = sizeOf (undefined :: CFloat)- sizeOf (VArg v) = sizeOf v-- alignment (IArg _) = alignment (undefined :: CUInt)- alignment (FArg _) = alignment (undefined :: CFloat)- alignment (VArg v) = alignment v-- poke p (IArg i) = poke (castPtr p) i- poke p (FArg f) = poke (castPtr p) f- poke p (VArg v) = poke (castPtr p) v-- peek _ = error "Can not peek Foreign.CUDA.Driver.FunParam"-------------------------------------------------------------------------------------- Execution Control------------------------------------------------------------------------------------- |--- Returns the value of the selected attribute requirement for the given kernel.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g5e92a1b0d8d1b82cb00dcfb2de15961b>----{-# INLINEABLE requires #-}-requires :: Fun -> FunAttribute -> IO Int-requires !fn !att = resultIfOk =<< cuFuncGetAttribute att fn--{-# INLINE cuFuncGetAttribute #-}-{# fun unsafe cuFuncGetAttribute- { alloca- `Int' peekIntConv*- , cFromEnum `FunAttribute'- , useFun `Fun' } -> `Status' cToEnum #}----- |--- On devices where the L1 cache and shared memory use the same hardware--- resources, this sets the preferred cache configuration for the given device--- function. This is only a preference; the driver is free to choose a different--- configuration as required to execute the function.------ Switching between configuration modes may insert a device-side--- synchronisation point for streamed kernel launches.------ Requires CUDA-3.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g40f8c11e81def95dc0072a375f965681>----{-# INLINEABLE setCacheConfigFun #-}-setCacheConfigFun :: Fun -> Cache -> IO ()-#if CUDA_VERSION < 3000-setCacheConfigFun _ _ = requireSDK 'setCacheConfigFun 3.0-#else-setCacheConfigFun !fn !pref = nothingIfOk =<< cuFuncSetCacheConfig fn pref--{-# INLINE cuFuncSetCacheConfig #-}-{# fun unsafe cuFuncSetCacheConfig- { useFun `Fun'- , cFromEnum `Cache' } -> `Status' cToEnum #}-#endif----- |--- Set the shared memory configuration of a device function.------ On devices with configurable shared memory banks, this will force all--- subsequent launches of the given device function to use the specified--- shared memory bank size configuration. On launch of the function, the--- shared memory configuration of the device will be temporarily changed if--- needed to suit the function configuration. Changes in shared memory--- configuration may introduction a device side synchronisation between--- kernel launches.------ Any per-function configuration specified by 'setSharedMemConfig' will--- override the context-wide configuration set with--- 'Foreign.CUDA.Driver.Context.Config.setSharedMem'.------ Changing the shared memory bank size will not increase shared memory--- usage or affect occupancy of kernels, but may have major effects on--- performance. Larger bank sizes will allow for greater potential--- bandwidth to shared memory, but will change what kinds of accesses to--- shared memory will result in bank conflicts.------ This function will do nothing on devices with fixed shared memory bank--- size.------ Requires CUDA-5.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g430b913f24970e63869635395df6d9f5>----{-# INLINEABLE setSharedMemConfigFun #-}-setSharedMemConfigFun :: Fun -> SharedMem -> IO ()-#if CUDA_VERSION < 5000-setSharedMemConfigFun _ _ = requireSDK 'setSharedMemConfigFun 5.0-#else-setSharedMemConfigFun !fun !pref = nothingIfOk =<< cuFuncSetSharedMemConfig fun pref--{-# INLINE cuFuncSetSharedMemConfig #-}-{# fun unsafe cuFuncSetSharedMemConfig- { useFun `Fun'- , cFromEnum `SharedMem'- }- -> `Status' cToEnum #}-#endif----- |--- Invoke a kernel on a @(gx * gy * gz)@ grid of blocks, where each block--- contains @(tx * ty * tz)@ threads and has access to a given number of bytes--- of shared memory. The launch may also be associated with a specific 'Stream'.------ In 'launchKernel', the number of kernel parameters and their offsets and--- sizes do not need to be specified, as this information is retrieved directly--- from the kernel's image. This requires the kernel to have been compiled with--- toolchain version 3.2 or later.------ The alternative 'launchKernel'' will pass the arguments in directly,--- requiring the application to know the size and alignment/padding of each--- kernel parameter.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1gb8f3dc3031b40da29d5f9a7139e52e15>----{-# INLINEABLE launchKernel #-}-{-# INLINEABLE launchKernel' #-}-launchKernel, launchKernel'- :: Fun -- ^ function to execute- -> (Int,Int,Int) -- ^ block grid dimension- -> (Int,Int,Int) -- ^ thread block shape- -> Int -- ^ shared memory (bytes)- -> Maybe Stream -- ^ (optional) stream to execute in- -> [FunParam] -- ^ list of function parameters- -> IO ()-#if CUDA_VERSION >= 4000-launchKernel !fn (!gx,!gy,!gz) (!tx,!ty,!tz) !sm !mst !args- = (=<<) nothingIfOk- $ withMany withFP args- $ \pa -> withArray pa- $ \pp -> cuLaunchKernel fn gx gy gz tx ty tz sm st pp nullPtr- where- !st = fromMaybe defaultStream mst-- withFP :: FunParam -> (Ptr FunParam -> IO b) -> IO b- withFP !p !f = case p of- IArg v -> with' v (f . castPtr)- FArg v -> with' v (f . castPtr)- VArg v -> with' v (f . castPtr)-- -- can't use the standard 'with' because 'alloca' will pass an undefined- -- dummy argument when determining 'sizeOf' and 'alignment', but sometimes- -- instances in Accelerate need to evaluate this argument.- --- with' :: Storable a => a -> (Ptr a -> IO b) -> IO b- with' !val !f =- allocaBytes (sizeOf val) $ \ptr -> do- poke ptr val- f ptr---launchKernel' !fn (!gx,!gy,!gz) (!tx,!ty,!tz) !sm !mst !args- = (=<<) nothingIfOk- $ with bytes- $ \pb -> withArray' args- $ \pa -> withArray0 nullPtr [buffer, castPtr pa, size, castPtr pb]- $ \pp -> cuLaunchKernel fn gx gy gz tx ty tz sm st nullPtr pp- where- buffer = wordPtrToPtr 0x01 -- CU_LAUNCH_PARAM_BUFFER_POINTER- size = wordPtrToPtr 0x02 -- CU_LAUNCH_PARAM_BUFFER_SIZE- bytes = foldl (\a x -> a + sizeOf x) 0 args- st = fromMaybe defaultStream mst-- -- can't use the standard 'withArray' because 'mallocArray' will pass- -- 'undefined' to 'sizeOf' when determining how many bytes to allocate, but- -- our Storable instance for FunParam needs to dispatch on each constructor,- -- hence evaluating the undefined.- --- withArray' !vals !f =- allocaBytes bytes $ \ptr -> do- pokeArray ptr vals- f ptr---{-# INLINE cuLaunchKernel #-}-{# fun unsafe cuLaunchKernel- { useFun `Fun'- , `Int', `Int', `Int'- , `Int', `Int', `Int'- , `Int'- , useStream `Stream'- , castPtr `Ptr (Ptr FunParam)'- , castPtr `Ptr (Ptr ())' } -> `Status' cToEnum #}--#else-launchKernel !fn (!gx,!gy,_) (!tx,!ty,!tz) !sm !mst !args = do- setParams fn args- setSharedSize fn (toInteger sm)- setBlockShape fn (tx,ty,tz)- launch fn (gx,gy) mst--launchKernel' = launchKernel-#endif-------------------------------------------------------------------------------------- Deprecated------------------------------------------------------------------------------------- |--- Invoke the kernel on a size @(w,h)@ grid of blocks. Each block contains the--- number of threads specified by a previous call to 'setBlockShape'. The launch--- may also be associated with a specific 'Stream'.----{-# INLINEABLE launch #-}-launch :: Fun -> (Int,Int) -> Maybe Stream -> IO ()-launch !fn (!w,!h) mst =- nothingIfOk =<< cuLaunchGridAsync fn w h (fromMaybe defaultStream mst)--{-# INLINE cuLaunchGridAsync #-}-{# fun unsafe cuLaunchGridAsync- { useFun `Fun'- , `Int'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Specify the @(x,y,z)@ dimensions of the thread blocks that are created when--- the given kernel function is launched.----{-# INLINEABLE setBlockShape #-}-setBlockShape :: Fun -> (Int,Int,Int) -> IO ()-setBlockShape !fn (!x,!y,!z) = nothingIfOk =<< cuFuncSetBlockShape fn x y z--{-# INLINE cuFuncSetBlockShape #-}-{# fun unsafe cuFuncSetBlockShape- { useFun `Fun'- , `Int'- , `Int'- , `Int' } -> `Status' cToEnum #}----- |--- Set the number of bytes of dynamic shared memory to be available to each--- thread block when the function is launched----{-# INLINEABLE setSharedSize #-}-setSharedSize :: Fun -> Integer -> IO ()-setSharedSize !fn !bytes = nothingIfOk =<< cuFuncSetSharedSize fn bytes--{-# INLINE cuFuncSetSharedSize #-}-{# fun unsafe cuFuncSetSharedSize- { useFun `Fun'- , cIntConv `Integer' } -> `Status' cToEnum #}----- |--- Set the parameters that will specified next time the kernel is invoked----{-# INLINEABLE setParams #-}-setParams :: Fun -> [FunParam] -> IO ()-setParams !fn !prs = do- zipWithM_ (set fn) offsets prs- nothingIfOk =<< cuParamSetSize fn (last offsets)- where- offsets = scanl (\a b -> a + size b) 0 prs-- size (IArg _) = sizeOf (undefined :: CUInt)- size (FArg _) = sizeOf (undefined :: CFloat)- size (VArg v) = sizeOf v-- set f o (IArg v) = nothingIfOk =<< cuParamSeti f o v- set f o (FArg v) = nothingIfOk =<< cuParamSetf f o v- set f o (VArg v) = with v $ \p -> (nothingIfOk =<< cuParamSetv f o p (sizeOf v))---{-# INLINE cuParamSetSize #-}-{# fun unsafe cuParamSetSize- { useFun `Fun'- , `Int' } -> `Status' cToEnum #}--{-# INLINE cuParamSeti #-}-{# fun unsafe cuParamSeti- { useFun `Fun'- , `Int'- , `Int32' } -> `Status' cToEnum #}--{-# INLINE cuParamSetf #-}-{# fun unsafe cuParamSetf- { useFun `Fun'- , `Int'- , `Float' } -> `Status' cToEnum #}--{-# INLINE cuParamSetv #-}-{# fun unsafe cuParamSetv- `Storable a' =>- { useFun `Fun'- , `Int'- , castPtr `Ptr a'- , `Int' } -> `Status' cToEnum #}--
− Foreign/CUDA/Driver/IPC/Event.chs
@@ -1,140 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.IPC.Event--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ IPC event management for low-level driver interface.------ Restricted to devices which support unified addressing on Linux--- operating systems.------ Since CUDA-4.1.--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.IPC.Event (-- IPCEvent,- export, open,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Event-import Foreign.CUDA.Internal.C2HS---- System-import Control.Monad-import Prelude--import Foreign.C-import Foreign.Ptr-import Foreign.ForeignPtr-import Foreign.Marshal-import Foreign.Storable-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A CUDA inter-process event handle.----newtype IPCEvent = IPCEvent { useIPCEvent :: IPCEventHandle }- deriving (Eq, Show)-------------------------------------------------------------------------------------- IPC event management------------------------------------------------------------------------------------- |--- Create an inter-process event handle for a previously allocated event.--- The event must be created with the 'Interprocess' and 'DisableTiming'--- event flags. The returned handle may then be sent to another process and--- 'open'ed to allow efficient hardware synchronisation between GPU work in--- other processes.------ After the event has been opened in the importing process, 'record',--- 'block', 'wait', 'query' may be used in either process.------ Performing operations on the imported event after the event has been--- 'destroy'ed in the exporting process is undefined.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gea02eadd12483de5305878b13288a86c>----{-# INLINEABLE export #-}-export :: Event -> IO IPCEvent-#if CUDA_VERSION < 4010-export _ = requireSDK 'create 4.1-#else-export !ev = do- h <- newIPCEventHandle- r <- cuIpcGetEventHandle h ev- resultIfOk (r, IPCEvent h)--{-# INLINE cuIpcGetEventHandle #-}-{# fun unsafe cuIpcGetEventHandle- { withForeignPtr* `IPCEventHandle'- , useEvent `Event'- }- -> `Status' cToEnum #}-#endif----- |--- Open an inter-process event handle for use in the current process,--- returning an event that can be used in the current process and behaving--- as a locally created event with the 'DisableTiming' flag specified.------ The event must be freed with 'destroy'. Performing operations on the--- imported event after the exported event has been 'destroy'ed in the--- exporting process is undefined.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf1d525918b6c643b99ca8c8e42e36c2e>----{-# INLINEABLE open #-}-open :: IPCEvent -> IO Event-#if CUDA_VERSION < 4010-open _ = requireSDK 'open 4.1-#else-open !ev = resultIfOk =<< cuIpcOpenEventHandle (useIPCEvent ev)--{-# INLINE cuIpcOpenEventHandle #-}-{# fun unsafe cuIpcOpenEventHandle- { alloca- `Event' peekEvent*- , withForeignPtr* `IPCEventHandle'- }- -> `Status' cToEnum #}- where- peekEvent = liftM Event . peek-#endif-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------type IPCEventHandle = ForeignPtr ()--newIPCEventHandle :: IO IPCEventHandle-#if CUDA_VERSION < 4010-newIPCEventHandle = requireSDK 'newIPCEventHandle 4.1-#else-newIPCEventHandle = mallocForeignPtrBytes {#sizeof CUipcEventHandle#}-#endif-
− Foreign/CUDA/Driver/IPC/Marshal.chs
@@ -1,177 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.IPC.Marshal--- Copyright : [2009..2015] Trevor L. McDonell--- License : BSD------ IPC memory management for low-level driver interface.------ Restricted to devices which support unified addressing on Linux--- operating systems.------ Since CUDA-4.0.--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.IPC.Marshal (-- -- ** IPC memory management- IPCDevicePtr, IPCFlag(..),- export, open, close,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Ptr-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS-import Foreign.CUDA.Driver.Marshal---- System-import Control.Monad-import Prelude--import Foreign.C-import Foreign.Ptr-import Foreign.ForeignPtr-import Foreign.Marshal-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A CUDA memory handle used for inter-process communication.----newtype IPCDevicePtr a = IPCDevicePtr { useIPCDevicePtr :: IPCMemHandle }- deriving (Eq, Show)----- |--- Flags for controlling IPC memory access----#if CUDA_VERSION < 4010-data IPCFlag-#else-{# enum CUipcMem_flags as IPCFlag- { underscoreToCase }- with prefix="CU_IPC_MEM" deriving (Eq, Show, Bounded) #}-#endif-------------------------------------------------------------------------------------- IPC memory management------------------------------------------------------------------------------------- |--- Create an inter-process memory handle for an existing device memory--- allocation. The handle can then be sent to another process and made--- available to that process via 'open'.------ Requires CUDA-4.1.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g6f1b5be767b275f016523b2ac49ebec1>----{-# INLINEABLE export #-}-export :: DevicePtr a -> IO (IPCDevicePtr a)-#if CUDA_VERSION < 4010-export _ = requireSDK 'export 4.1-#else-export !dptr = do- h <- newIPCMemHandle- r <- cuIpcGetMemHandle h dptr- resultIfOk (r, IPCDevicePtr h)--{-# INLINE cuIpcGetMemHandle #-}-{# fun unsafe cuIpcGetMemHandle- { withForeignPtr* `IPCMemHandle'- , useDeviceHandle `DevicePtr a'- }- -> `Status' cToEnum #}-#endif----- |--- Open an inter-process memory handle exported from another process,--- returning a device pointer usable in the current process.------ Maps memory exported by another process with 'create' into the current--- device address space. For contexts on different devices, 'open' can--- attempt to enable peer access if the user called--- 'Foreign.CUDA.Driver.Context.Peer.add', and is controlled by the--- 'LazyEnablePeerAccess' flag.------ Each handle from a given device and context may only be 'open'ed by one--- context per device per other process. Memory returned by 'open' must be--- freed via 'close'.------ Requires CUDA-4.1.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1ga8bd126fcff919a0c996b7640f197b79>----{-# INLINEABLE open #-}-open :: IPCDevicePtr a -> [IPCFlag]-> IO (DevicePtr a)-#if CUDA_VERSION < 4010-open _ _ = requireSDK 'open 4.1-#else-open !hdl !flags = resultIfOk =<< cuIpcOpenMemHandle (useIPCDevicePtr hdl) flags--{-# INLINE cuIpcOpenMemHandle #-}-{# fun unsafe cuIpcOpenMemHandle- { alloca- `DevicePtr a' peekDeviceHandle*- , withForeignPtr* `IPCMemHandle'- , combineBitMasks `[IPCFlag]'- }- -> `Status' cToEnum #}-#endif----- |--- Close and unmap memory returned by 'open'. The original allocation in--- the exporting process as well as imported mappings in other processes--- are unaffected.------ Any resources used to enable peer access will be freed if this is the--- last mapping using them.------ Requires CUDA-4.1.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gd6f5d5bcf6376c6853b64635b0157b9e>----{-# INLINEABLE close #-}-close :: DevicePtr a -> IO ()-#if CUDA_VERSION < 4010-close _ = requireSDK 'close 4.1-#else-close !dptr = nothingIfOk =<< cuIpcCloseMemHandle dptr--{-# INLINE cuIpcCloseMemHandle #-}-{# fun unsafe cuIpcCloseMemHandle- { useDeviceHandle `DevicePtr a'- }- -> `Status' cToEnum #}-#endif-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------type IPCMemHandle = ForeignPtr ()--newIPCMemHandle :: IO IPCMemHandle-#if CUDA_VERSION < 4010-newIPCMemHandle = requireSDK 'newIPCMemHandle 4.1-#else-newIPCMemHandle = mallocForeignPtrBytes {#sizeof CUipcMemHandle#}-#endif-
− Foreign/CUDA/Driver/Marshal.chs
@@ -1,1117 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_HADDOCK prune #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Marshal--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Memory management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Marshal (-- -- * Host Allocation- AllocFlag(..),- mallocHostArray, mallocHostForeignPtr, freeHost,- registerArray, unregisterArray,-- -- * Device Allocation- mallocArray, allocaArray, free,-- -- * Unified Memory Allocation- AttachFlag(..),- mallocManagedArray,-- -- * Marshalling- peekArray, peekArrayAsync, peekArray2D, peekArray2DAsync, peekListArray,- pokeArray, pokeArrayAsync, pokeArray2D, pokeArray2DAsync, pokeListArray,- copyArray, copyArrayAsync, copyArray2D, copyArray2DAsync,- copyArrayPeer, copyArrayPeerAsync,-- -- * Combined Allocation and Marshalling- newListArray, newListArrayLen,- withListArray, withListArrayLen,-- -- * Utility- memset, memsetAsync,- getDevicePtr, getBasePtr, getMemInfo,-- -- Internal- useDeviceHandle, peekDeviceHandle--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Ptr-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Stream ( Stream(..), defaultStream )-import Foreign.CUDA.Driver.Context.Base ( Context(..) )-import Foreign.CUDA.Internal.C2HS---- System-import Data.Int-import Data.Maybe-import Data.Word-import Unsafe.Coerce-import Control.Applicative-import Control.Exception-import Prelude--import Foreign.C-import Foreign.Ptr-import Foreign.ForeignPtr-import Foreign.Storable-import qualified Foreign.Marshal as F--#c-typedef enum CUmemhostalloc_option_enum {- CU_MEMHOSTALLOC_OPTION_PORTABLE = CU_MEMHOSTALLOC_PORTABLE,- CU_MEMHOSTALLOC_OPTION_DEVICE_MAPPED = CU_MEMHOSTALLOC_DEVICEMAP,- CU_MEMHOSTALLOC_OPTION_WRITE_COMBINED = CU_MEMHOSTALLOC_WRITECOMBINED-} CUmemhostalloc_option;-#endc-------------------------------------------------------------------------------------- Host Allocation------------------------------------------------------------------------------------- |--- Options for host allocation----{# enum CUmemhostalloc_option as AllocFlag- { underscoreToCase }- with prefix="CU_MEMHOSTALLOC_OPTION" deriving (Eq, Show, Bounded) #}---- |--- Allocate a section of linear memory on the host which is page-locked and--- directly accessible from the device. The storage is sufficient to hold the--- given number of elements of a storable type.------ Note that since the amount of pageable memory is thusly reduced, overall--- system performance may suffer. This is best used sparingly to allocate--- staging areas for data exchange.------ Host memory allocated in this way is automatically and immediately--- accessible to all contexts on all devices which support unified--- addressing.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gdd8311286d2c2691605362c689bc64e0>----{-# INLINEABLE mallocHostArray #-}-mallocHostArray :: Storable a => [AllocFlag] -> Int -> IO (HostPtr a)-mallocHostArray !flags = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (HostPtr a')- doMalloc x !n = resultIfOk =<< cuMemHostAlloc (n * sizeOf x) flags---- |--- As 'mallocHostArray', but return a 'ForeignPtr' instead. The array will be--- deallocated automatically once the last reference to the 'ForeignPtr' is--- dropped.----{-# INLINEABLE mallocHostForeignPtr #-}-{-# SPECIALISE mallocHostForeignPtr :: [AllocFlag] -> Int -> IO (ForeignPtr Word8) #-}-mallocHostForeignPtr :: Storable a => [AllocFlag] -> Int -> IO (ForeignPtr a)-mallocHostForeignPtr !flags !size = do- HostPtr ptr <- mallocHostArray flags size- newForeignPtr finalizerMemFreeHost ptr--{-# INLINE cuMemHostAlloc #-}-{# fun unsafe cuMemHostAlloc- { alloca'- `HostPtr a' peekHP*- , `Int'- , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}- where- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)- peekHP !p = HostPtr . castPtr <$> peek p---- Pointer to the foreign function to release host arrays, which may be used as--- a finalizer. Technically this function has a non-void return type, but I am--- hoping that that doesn't matter...----foreign import ccall "&cuMemFreeHost" finalizerMemFreeHost :: FinalizerPtr a---- |--- Free a section of page-locked host memory.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g62e0fdbe181dab6b1c90fa1a51c7b92c>----{-# INLINEABLE freeHost #-}-freeHost :: HostPtr a -> IO ()-freeHost !p = nothingIfOk =<< cuMemFreeHost p--{-# INLINE cuMemFreeHost #-}-{# fun unsafe cuMemFreeHost- { useHP `HostPtr a' } -> `Status' cToEnum #}- where- useHP = castPtr . useHostPtr----- |--- Page-locks the specified array (on the host) and maps it for the device(s) as--- specified by the given allocation flags. Subsequently, the memory is accessed--- directly by the device so can be read and written with much higher bandwidth--- than pageable memory that has not been registered. The memory range is added--- to the same tracking mechanism as 'mallocHostArray' to automatically--- accelerate calls to functions such as 'pokeArray'.------ Note that page-locking excessive amounts of memory may degrade system--- performance, since it reduces the amount of pageable memory available. This--- is best used sparingly to allocate staging areas for data exchange.------ This function has limited support on Mac OS X. OS 10.7 or later is--- required.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf0a9fe11544326dabd743b7aa6b54223>----{-# INLINEABLE registerArray #-}-registerArray :: Storable a => [AllocFlag] -> Int -> Ptr a -> IO (HostPtr a)-#if CUDA_VERSION < 4000-registerArray _ _ _ = requireSDK 'registerArray 4.0-#else-registerArray !flags !n = go undefined- where- go :: Storable b => b -> Ptr b -> IO (HostPtr b)- go x !p = do- status <- cuMemHostRegister p (n * sizeOf x) flags- resultIfOk (status,HostPtr p)--{-# INLINE cuMemHostRegister #-}-{# fun unsafe cuMemHostRegister- { castPtr `Ptr a'- , `Int'- , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}-#endif----- |--- Unmaps the memory from the given pointer, and makes it pageable again.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g63f450c8125359be87b7623b1c0b2a14>----{-# INLINEABLE unregisterArray #-}-unregisterArray :: HostPtr a -> IO (Ptr a)-#if CUDA_VERSION < 4000-unregisterArray _ = requireSDK 'unregisterArray 4.0-#else-unregisterArray (HostPtr !p) = do- status <- cuMemHostUnregister p- resultIfOk (status,p)--{-# INLINE cuMemHostUnregister #-}-{# fun unsafe cuMemHostUnregister- { castPtr `Ptr a' } -> `Status' cToEnum #}-#endif-------------------------------------------------------------------------------------- Device Allocation------------------------------------------------------------------------------------- |--- Allocate a section of linear memory on the device, and return a reference to--- it. The memory is sufficient to hold the given number of elements of storable--- type. It is suitably aligned for any type, and is not cleared.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gb82d2a09844a58dd9e744dc31e8aa467>----{-# INLINEABLE mallocArray #-}-mallocArray :: Storable a => Int -> IO (DevicePtr a)-mallocArray = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')- doMalloc x !n = resultIfOk =<< cuMemAlloc (n * sizeOf x)--{-# INLINE cuMemAlloc #-}-{# fun unsafe cuMemAlloc- { alloca'- `DevicePtr a' peekDeviceHandle*- , `Int' } -> `Status' cToEnum #}- where- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)----- |--- Execute a computation on the device, passing a pointer to a temporarily--- allocated block of memory sufficient to hold the given number of elements of--- storable type. The memory is freed when the computation terminates (normally--- or via an exception), so the pointer must not be used after this.------ Note that kernel launches can be asynchronous, so you may want to add a--- synchronisation point using 'Foreign.CUDA.Driver.Context.sync' as part--- of the continuation.----{-# INLINEABLE allocaArray #-}-allocaArray :: Storable a => Int -> (DevicePtr a -> IO b) -> IO b-allocaArray !n = bracket (mallocArray n) free----- |--- Release a section of device memory.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g89b3f154e17cc89b6eea277dbdf5c93a>----{-# INLINEABLE free #-}-free :: DevicePtr a -> IO ()-free !dp = nothingIfOk =<< cuMemFree dp--{-# INLINE cuMemFree #-}-{# fun unsafe cuMemFree- { useDeviceHandle `DevicePtr a' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Unified memory allocations------------------------------------------------------------------------------------- |--- Options for unified memory allocations----#if CUDA_VERSION < 6000-data AttachFlag-#else-{# enum CUmemAttach_flags as AttachFlag- { underscoreToCase }- with prefix="CU_MEM_ATTACH_OPTION" deriving (Eq, Show, Bounded) #}-#endif---- |--- Allocates memory that will be automatically managed by the Unified Memory--- system. The returned pointer is valid on the CPU and on all GPUs which--- supported managed memory. All accesses to this pointer must obey the--- Unified Memory programming model.------ On a multi-GPU system with peer-to-peer support, where multiple GPUs--- support managed memory, the physical storage is created on the GPU which--- is active at the time 'mallocManagedArray' is called. All other GPUs--- will access the array at reduced bandwidth via peer mapping over the--- PCIe bus. The Unified Memory system does not migrate memory between--- GPUs.------ On a multi-GPU system where multiple GPUs support managed memory, but--- not all pairs of such GPUs have peer-to-peer support between them, the--- physical storage is allocated in system memory (zero-copy memory) and--- all GPUs will access the data at reduced bandwidth over the PCIe bus.------ Requires CUDA-6.0------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gb347ded34dc326af404aa02af5388a32>----{-# INLINEABLE mallocManagedArray #-}-mallocManagedArray :: Storable a => [AttachFlag] -> Int -> IO (DevicePtr a)-#if CUDA_VERSION < 6000-mallocManagedArray _ _ = requireSDK 'mallocManagedArray 6.0-#else-mallocManagedArray !flags = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')- doMalloc x !n = resultIfOk =<< cuMemAllocManaged (n * sizeOf x) flags--{-# INLINE cuMemAllocManaged #-}-{# fun unsafe cuMemAllocManaged- { alloca'- `DevicePtr a' peekDeviceHandle*- , `Int'- , combineBitMasks `[AttachFlag]' } -> `Status' cToEnum #}- where- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)-#endif-------------------------------------------------------------------------------------- Marshalling------------------------------------------------------------------------------------- Device -> Host--- ------------------ |--- Copy a number of elements from the device to host memory. This is a--- synchronous operation.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g3480368ee0208a98f75019c9a8450893>----{-# INLINEABLE peekArray #-}-peekArray :: Storable a => Int -> DevicePtr a -> Ptr a -> IO ()-peekArray !n !dptr !hptr = doPeek undefined dptr- where- doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()- doPeek x _ = nothingIfOk =<< cuMemcpyDtoH hptr dptr (n * sizeOf x)--{-# INLINE cuMemcpyDtoH #-}-{# fun cuMemcpyDtoH- { castPtr `Ptr a'- , useDeviceHandle `DevicePtr a'- , `Int' } -> `Status' cToEnum #}----- |--- Copy memory from the device asynchronously, possibly associated with a--- particular stream. The destination host memory must be page-locked.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g56f30236c7c5247f8e061b59d3268362>----{-# INLINEABLE peekArrayAsync #-}-peekArrayAsync :: Storable a => Int -> DevicePtr a -> HostPtr a -> Maybe Stream -> IO ()-peekArrayAsync !n !dptr !hptr !mst = doPeek undefined dptr- where- doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()- doPeek x _ = nothingIfOk =<< cuMemcpyDtoHAsync hptr dptr (n * sizeOf x) (fromMaybe defaultStream mst)--{-# INLINE cuMemcpyDtoHAsync #-}-{# fun cuMemcpyDtoHAsync- { useHP `HostPtr a'- , useDeviceHandle `DevicePtr a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}- where- useHP = castPtr . useHostPtr----- |--- Copy a 2D array from the device to the host.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>----{-# INLINEABLE peekArray2D #-}-peekArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> Ptr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> IO ()-peekArray2D !w !h !dptr !dw !dx !dy !hptr !hw !hx !hy = doPeek undefined dptr- where- doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()- doPeek x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- in- nothingIfOk =<< cuMemcpy2DDtoH hptr hw' hx' hy dptr dw' dx' dy w' h--{-# INLINE cuMemcpy2DDtoH #-}-{# fun cuMemcpy2DDtoH- { castPtr `Ptr a'- , `Int'- , `Int'- , `Int'- , useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- }- -> `Status' cToEnum #}----- |--- Copy a 2D array from the device to the host asynchronously, possibly--- associated with a particular execution stream. The destination host memory--- must be page-locked.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>----{-# INLINEABLE peekArray2DAsync #-}-peekArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> HostPtr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> Maybe Stream -- ^ stream to associate to- -> IO ()-peekArray2DAsync !w !h !dptr !dw !dx !dy !hptr !hw !hx !hy !mst = doPeek undefined dptr- where- doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()- doPeek x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- st = fromMaybe defaultStream mst- in- nothingIfOk =<< cuMemcpy2DDtoHAsync hptr hw' hx' hy dptr dw' dx' dy w' h st--{-# INLINE cuMemcpy2DDtoHAsync #-}-{# fun cuMemcpy2DDtoHAsync- { useHP `HostPtr a'- , `Int'- , `Int'- , `Int'- , useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- , useStream `Stream'- }- -> `Status' cToEnum #}- where- useHP = castPtr . useHostPtr----- |--- Copy a number of elements from the device into a new Haskell list. Note that--- this requires two memory copies: firstly from the device into a heap--- allocated array, and from there marshalled into a list.----{-# INLINEABLE peekListArray #-}-peekListArray :: Storable a => Int -> DevicePtr a -> IO [a]-peekListArray !n !dptr =- F.allocaArray n $ \p -> do- peekArray n dptr p- F.peekArray n p----- Host -> Device--- ------------------ |--- Copy a number of elements onto the device. This is a synchronous operation.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4d32266788c440b0220b1a9ba5795169>----{-# INLINEABLE pokeArray #-}-pokeArray :: Storable a => Int -> Ptr a -> DevicePtr a -> IO ()-pokeArray !n !hptr !dptr = doPoke undefined dptr- where- doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()- doPoke x _ = nothingIfOk =<< cuMemcpyHtoD dptr hptr (n * sizeOf x)--{-# INLINE cuMemcpyHtoD #-}-{# fun cuMemcpyHtoD- { useDeviceHandle `DevicePtr a'- , castPtr `Ptr a'- , `Int' } -> `Status' cToEnum #}----- |--- Copy memory onto the device asynchronously, possibly associated with a--- particular stream. The source host memory must be page-locked.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g1572263fe2597d7ba4f6964597a354a3>----{-# INLINEABLE pokeArrayAsync #-}-pokeArrayAsync :: Storable a => Int -> HostPtr a -> DevicePtr a -> Maybe Stream -> IO ()-pokeArrayAsync !n !hptr !dptr !mst = dopoke undefined dptr- where- dopoke :: Storable a' => a' -> DevicePtr a' -> IO ()- dopoke x _ = nothingIfOk =<< cuMemcpyHtoDAsync dptr hptr (n * sizeOf x) (fromMaybe defaultStream mst)--{-# INLINE cuMemcpyHtoDAsync #-}-{# fun cuMemcpyHtoDAsync- { useDeviceHandle `DevicePtr a'- , useHP `HostPtr a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}- where- useHP = castPtr . useHostPtr----- |--- Copy a 2D array from the host to the device.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>----{-# INLINEABLE pokeArray2D #-}-pokeArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> Ptr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> IO ()-pokeArray2D !w !h !hptr !hw !hx !hy !dptr !dw !dx !dy = doPoke undefined dptr- where- doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()- doPoke x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- in- nothingIfOk =<< cuMemcpy2DHtoD dptr dw' dx' dy hptr hw' hx' hy w' h--{-# INLINE cuMemcpy2DHtoD #-}-{# fun cuMemcpy2DHtoD- { useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , castPtr `Ptr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- }- -> `Status' cToEnum #}----- |--- Copy a 2D array from the host to the device asynchronously, possibly--- associated with a particular execution stream. The source host memory must be--- page-locked.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>----{-# INLINEABLE pokeArray2DAsync #-}-pokeArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> HostPtr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> Maybe Stream -- ^ stream to associate to- -> IO ()-pokeArray2DAsync !w !h !hptr !hw !hx !hy !dptr !dw !dx !dy !mst = doPoke undefined dptr- where- doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()- doPoke x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- st = fromMaybe defaultStream mst- in- nothingIfOk =<< cuMemcpy2DHtoDAsync dptr dw' dx' dy hptr hw' hx' hy w' h st--{-# INLINE cuMemcpy2DHtoDAsync #-}-{# fun cuMemcpy2DHtoDAsync- { useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , useHP `HostPtr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- , useStream `Stream'- }- -> `Status' cToEnum #}- where- useHP = castPtr . useHostPtr----- |--- Write a list of storable elements into a device array. The device array must--- be sufficiently large to hold the entire list. This requires two marshalling--- operations.----{-# INLINEABLE pokeListArray #-}-pokeListArray :: Storable a => [a] -> DevicePtr a -> IO ()-pokeListArray !xs !dptr = F.withArrayLen xs $ \ !len !p -> pokeArray len p dptr----- Device -> Device--- -------------------- |--- Copy the given number of elements from the first device array (source) to the--- second device (destination). The copied areas may not overlap. This operation--- is asynchronous with respect to the host, but will never overlap with kernel--- execution.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g1725774abf8b51b91945f3336b778c8b>----{-# INLINEABLE copyArray #-}-copyArray :: Storable a => Int -> DevicePtr a -> DevicePtr a -> IO ()-copyArray !n = docopy undefined- where- docopy :: Storable a' => a' -> DevicePtr a' -> DevicePtr a' -> IO ()- docopy x src dst = nothingIfOk =<< cuMemcpyDtoD dst src (n * sizeOf x)--{-# INLINE cuMemcpyDtoD #-}-{# fun unsafe cuMemcpyDtoD- { useDeviceHandle `DevicePtr a'- , useDeviceHandle `DevicePtr a'- , `Int' } -> `Status' cToEnum #}----- |--- Copy the given number of elements from the first device array (source) to the--- second device array (destination). The copied areas may not overlap. The--- operation is asynchronous with respect to the host, and can be asynchronous--- to other device operations by associating it with a particular stream.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g39ea09ba682b8eccc9c3e0c04319b5c8>----{-# INLINEABLE copyArrayAsync #-}-copyArrayAsync :: Storable a => Int -> DevicePtr a -> DevicePtr a -> Maybe Stream -> IO ()-copyArrayAsync !n !src !dst !mst = docopy undefined src- where- docopy :: Storable a' => a' -> DevicePtr a' -> IO ()- docopy x _ = nothingIfOk =<< cuMemcpyDtoDAsync dst src (n * sizeOf x) (fromMaybe defaultStream mst)--{-# INLINE cuMemcpyDtoDAsync #-}-{# fun unsafe cuMemcpyDtoDAsync- { useDeviceHandle `DevicePtr a'- , useDeviceHandle `DevicePtr a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Copy a 2D array from the first device array (source) to the second device--- array (destination). The copied areas must not overlap. This operation is--- asynchronous with respect to the host, but will never overlap with kernel--- execution.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>----{-# INLINEABLE copyArray2D #-}-copyArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> IO ()-copyArray2D !w !h !src !hw !hx !hy !dst !dw !dx !dy = doCopy undefined dst- where- doCopy :: Storable a' => a' -> DevicePtr a' -> IO ()- doCopy x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- in- nothingIfOk =<< cuMemcpy2DDtoD dst dw' dx' dy src hw' hx' hy w' h--{-# INLINE cuMemcpy2DDtoD #-}-{# fun unsafe cuMemcpy2DDtoD- { useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- }- -> `Status' cToEnum #}----- |--- Copy a 2D array from the first device array (source) to the second device--- array (destination). The copied areas may not overlap. The operation is--- asynchronous with respect to the host, and can be asynchronous to other--- device operations by associating it with a particular execution stream.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>----{-# INLINEABLE copyArray2DAsync #-}-copyArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> Int -- ^ source x-coordinate- -> Int -- ^ source y-coordinate- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Int -- ^ destination x-coordinate- -> Int -- ^ destination y-coordinate- -> Maybe Stream -- ^ stream to associate to- -> IO ()-copyArray2DAsync !w !h !src !hw !hx !hy !dst !dw !dx !dy !mst = doCopy undefined dst- where- doCopy :: Storable a' => a' -> DevicePtr a' -> IO ()- doCopy x _ =- let bytes = sizeOf x- w' = w * bytes- hw' = hw * bytes- hx' = hx * bytes- dw' = dw * bytes- dx' = dx * bytes- st = fromMaybe defaultStream mst- in- nothingIfOk =<< cuMemcpy2DDtoDAsync dst dw' dx' dy src hw' hx' hy w' h st--{-# INLINE cuMemcpy2DDtoDAsync #-}-{# fun unsafe cuMemcpy2DDtoDAsync- { useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int'- , `Int'- , `Int'- , useStream `Stream'- }- -> `Status' cToEnum #}------ Context -> Context--- ---------------------- |--- Copies an array from device memory in one context to device memory in another--- context. Note that this function is asynchronous with respect to the host,--- but serialised with respect to all pending and future asynchronous work in--- the source and destination contexts. To avoid this synchronisation, use--- 'copyArrayPeerAsync' instead.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1ge1f5c7771544fee150ada8853c7cbf4a>----{-# INLINEABLE copyArrayPeer #-}-copyArrayPeer :: Storable a- => Int -- ^ number of array elements- -> DevicePtr a -> Context -- ^ source array and context- -> DevicePtr a -> Context -- ^ destination array and context- -> IO ()-#if CUDA_VERSION < 4000-copyArrayPeer _ _ _ _ _ = requireSDK 'copyArrayPeer 4.0-#else-copyArrayPeer !n !src !srcCtx !dst !dstCtx = go undefined src dst- where- go :: Storable b => b -> DevicePtr b -> DevicePtr b -> IO ()- go x _ _ = nothingIfOk =<< cuMemcpyPeer dst dstCtx src srcCtx (n * sizeOf x)--{-# INLINE cuMemcpyPeer #-}-{# fun unsafe cuMemcpyPeer- { useDeviceHandle `DevicePtr a'- , useContext `Context'- , useDeviceHandle `DevicePtr a'- , useContext `Context'- , `Int' } -> `Status' cToEnum #}-#endif----- |--- Copies from device memory in one context to device memory in another context.--- Note that this function is asynchronous with respect to the host and all work--- in other streams and devices.------ Requires CUDA-4.0.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g82fcecb38018e64b98616a8ac30112f2>----{-# INLINEABLE copyArrayPeerAsync #-}-copyArrayPeerAsync :: Storable a- => Int -- ^ number of array elements- -> DevicePtr a -> Context -- ^ source array and context- -> DevicePtr a -> Context -- ^ destination array and device context- -> Maybe Stream -- ^ stream to associate with- -> IO ()-#if CUDA_VERSION < 4000-copyArrayPeerAsync _ _ _ _ _ _ = requireSDK 'copyArrayPeerAsync 4.0-#else-copyArrayPeerAsync !n !src !srcCtx !dst !dstCtx !st = go undefined src dst- where- go :: Storable b => b -> DevicePtr b -> DevicePtr b -> IO ()- go x _ _ = nothingIfOk =<< cuMemcpyPeerAsync dst dstCtx src srcCtx (n * sizeOf x) stream- stream = fromMaybe defaultStream st--{-# INLINE cuMemcpyPeerAsync #-}-{# fun unsafe cuMemcpyPeerAsync- { useDeviceHandle `DevicePtr a'- , useContext `Context'- , useDeviceHandle `DevicePtr a'- , useContext `Context'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}-#endif-------------------------------------------------------------------------------------- Combined Allocation and Marshalling------------------------------------------------------------------------------------- |--- Write a list of storable elements into a newly allocated device array,--- returning the device pointer together with the number of elements that were--- written. Note that this requires two memory copies: firstly from a Haskell--- list to a heap allocated array, and from there onto the graphics device. The--- memory should be 'free'd when no longer required.----{-# INLINEABLE newListArrayLen #-}-newListArrayLen :: Storable a => [a] -> IO (DevicePtr a, Int)-newListArrayLen xs =- F.withArrayLen xs $ \len p ->- bracketOnError (mallocArray len) free $ \d_xs -> do- pokeArray len p d_xs- return (d_xs, len)----- |--- Write a list of storable elements into a newly allocated device array. This--- is 'newListArrayLen' composed with 'fst'.----{-# INLINEABLE newListArray #-}-newListArray :: Storable a => [a] -> IO (DevicePtr a)-newListArray xs = fst `fmap` newListArrayLen xs----- |--- Temporarily store a list of elements into a newly allocated device array. An--- IO action is applied to to the array, the result of which is returned.--- Similar to 'newListArray', this requires copying the data twice.------ As with 'allocaArray', the memory is freed once the action completes, so you--- should not return the pointer from the action, and be wary of asynchronous--- kernel execution.----{-# INLINEABLE withListArray #-}-withListArray :: Storable a => [a] -> (DevicePtr a -> IO b) -> IO b-withListArray xs = withListArrayLen xs . const----- |--- A variant of 'withListArray' which also supplies the number of elements in--- the array to the applied function----{-# INLINEABLE withListArrayLen #-}-withListArrayLen :: Storable a => [a] -> (Int -> DevicePtr a -> IO b) -> IO b-withListArrayLen xs f =- bracket (newListArrayLen xs) (free . fst) (uncurry . flip $ f)------ XXX: Will this attempt to double-free the device array on error (together--- with newListArrayLen)?----------------------------------------------------------------------------------------- Utility------------------------------------------------------------------------------------- |--- Set a number of data elements to the specified value, which may be either 8-,--- 16-, or 32-bits wide.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g6e582bf866e9e2fb014297bfaf354d7b>------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g7d805e610054392a4d11e8a8bf5eb35c>------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g983e8d8759acd1b64326317481fbf132>----{-# INLINEABLE memset #-}-memset :: Storable a => DevicePtr a -> Int -> a -> IO ()-memset !dptr !n !val = case sizeOf val of- 1 -> nothingIfOk =<< cuMemsetD8 dptr val n- 2 -> nothingIfOk =<< cuMemsetD16 dptr val n- 4 -> nothingIfOk =<< cuMemsetD32 dptr val n- _ -> cudaError "can only memset 8-, 16-, and 32-bit values"------- We use unsafe coerce below to reinterpret the bits of the value to memset as,--- into the integer type required by the setting functions.----{-# INLINE cuMemsetD8 #-}-{# fun unsafe cuMemsetD8- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int' } -> `Status' cToEnum #}--{-# INLINE cuMemsetD16 #-}-{# fun unsafe cuMemsetD16- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int' } -> `Status' cToEnum #}--{-# INLINE cuMemsetD32 #-}-{# fun unsafe cuMemsetD32- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int' } -> `Status' cToEnum #}----- |--- Set the number of data elements to the specified value, which may be either--- 8-, 16-, or 32-bits wide. The operation is asynchronous and may optionally be--- associated with a stream.------ Requires CUDA-3.2.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gaef08a7ccd61112f94e82f2b30d43627>------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf731438877dd8ec875e4c43d848c878c>------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g58229da5d30f1c0cdf667b320ec2c0f5>----{-# INLINEABLE memsetAsync #-}-memsetAsync :: Storable a => DevicePtr a -> Int -> a -> Maybe Stream -> IO ()-#if CUDA_VERSION < 3020-memsetAsync _ _ _ _ = requireSDK 'memsetAsync 3.2-#else-memsetAsync !dptr !n !val !mst = case sizeOf val of- 1 -> nothingIfOk =<< cuMemsetD8Async dptr val n stream- 2 -> nothingIfOk =<< cuMemsetD16Async dptr val n stream- 4 -> nothingIfOk =<< cuMemsetD32Async dptr val n stream- _ -> cudaError "can only memset 8-, 16-, and 32-bit values"- where- stream = fromMaybe defaultStream mst--{-# INLINE cuMemsetD8Async #-}-{# fun unsafe cuMemsetD8Async- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}--{-# INLINE cuMemsetD16Async #-}-{# fun unsafe cuMemsetD16Async- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}--{-# INLINE cuMemsetD32Async #-}-{# fun unsafe cuMemsetD32Async- { useDeviceHandle `DevicePtr a'- , unsafeCoerce `a'- , `Int'- , useStream `Stream' } -> `Status' cToEnum #}-#endif----- |--- Return the device pointer associated with a mapped, pinned host buffer, which--- was allocated with the 'DeviceMapped' option by 'mallocHostArray'.------ Currently, no options are supported and this must be empty.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g57a39e5cba26af4d06be67fc77cc62f0>----{-# INLINEABLE getDevicePtr #-}-getDevicePtr :: [AllocFlag] -> HostPtr a -> IO (DevicePtr a)-getDevicePtr !flags !hp = resultIfOk =<< cuMemHostGetDevicePointer hp flags--{-# INLINE cuMemHostGetDevicePointer #-}-{# fun unsafe cuMemHostGetDevicePointer- { alloca'- `DevicePtr a' peekDeviceHandle*- , useHP `HostPtr a'- , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}- where- alloca' = F.alloca- useHP = castPtr . useHostPtr----- |--- Return the base address and allocation size of the given device pointer.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g64fee5711274a2a0573a789c94d8299b>----{-# INLINEABLE getBasePtr #-}-getBasePtr :: DevicePtr a -> IO (DevicePtr a, Int64)-getBasePtr !dptr = do- (status,base,size) <- cuMemGetAddressRange dptr- resultIfOk (status, (base,size))--{-# INLINE cuMemGetAddressRange #-}-{# fun unsafe cuMemGetAddressRange- { alloca'- `DevicePtr a' peekDeviceHandle*- , alloca'- `Int64' peekIntConv*- , useDeviceHandle `DevicePtr a' } -> `Status' cToEnum #}- where- alloca' :: Storable a => (Ptr a -> IO b) -> IO b- alloca' = F.alloca---- |--- Return the amount of free and total memory respectively available to the--- current context (bytes).------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g808f555540d0143a331cc42aa98835c0>----{-# INLINEABLE getMemInfo #-}-getMemInfo :: IO (Int64, Int64)-getMemInfo = do- (!status,!f,!t) <- cuMemGetInfo- resultIfOk (status,(f,t))--{-# INLINE cuMemGetInfo #-}-{# fun unsafe cuMemGetInfo- { alloca'- `Int64' peekIntConv*- , alloca'- `Int64' peekIntConv* } -> `Status' cToEnum #}- where- alloca' = F.alloca-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------type DeviceHandle = {# type CUdeviceptr #}---- Lift an opaque handle to a typed DevicePtr representation. This occasions--- arcane distinctions for the different driver versions and Tesla (compute 1.x)--- and Fermi (compute 2.x) class architectures on 32- and 64-bit hosts.----{-# INLINE peekDeviceHandle #-}-peekDeviceHandle :: Ptr DeviceHandle -> IO (DevicePtr a)-peekDeviceHandle !p = DevicePtr . intPtrToPtr . fromIntegral <$> peek p---- Use a device pointer as an opaque handle type----{-# INLINE useDeviceHandle #-}-useDeviceHandle :: DevicePtr a -> DeviceHandle-useDeviceHandle = fromIntegral . ptrToIntPtr . useDevicePtr-
− Foreign/CUDA/Driver/Module.hs
@@ -1,20 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Module--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Module management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Module (-- module Foreign.CUDA.Driver.Module.Base,- module Foreign.CUDA.Driver.Module.Query,--) where--import Foreign.CUDA.Driver.Module.Base hiding ( JITOptionInternal(..), useModule, jitOptionUnpack, jitTargetOfCompute )-import Foreign.CUDA.Driver.Module.Query-
− Foreign/CUDA/Driver/Module/Base.chs
@@ -1,322 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_HADDOCK prune #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Module.Base--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Module loading for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Module.Base (-- -- * Module Management- Module(..),- JITOption(..), JITTarget(..), JITResult(..), JITFallback(..), JITInputType(..),- JITOptionInternal(..),-- -- ** Loading and unloading modules- loadFile,- loadData, loadDataFromPtr,- loadDataEx, loadDataFromPtrEx,- unload,-- -- Internal- jitOptionUnpack, jitTargetOfCompute,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Analysis.Device-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Unsafe.Coerce--import Control.Monad ( liftM )-import Data.ByteString.Char8 ( ByteString )-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Internal as B-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A reference to a Module object, containing collections of device functions----newtype Module = Module { useModule :: {# type CUmodule #}}- deriving (Eq, Show)---- |--- Just-in-time compilation and linking options----data JITOption- = MaxRegisters !Int -- ^ maximum number of registers per thread- | ThreadsPerBlock !Int -- ^ number of threads per block to target for- | OptimisationLevel !Int -- ^ level of optimisation to apply (1-4, default 4)- | Target !Compute -- ^ compilation target, otherwise determined from context- | FallbackStrategy !JITFallback -- ^ fallback strategy if matching cubin not found- | GenerateDebugInfo -- ^ generate debug info (-g) (requires cuda >= 5.5)- | GenerateLineInfo -- ^ generate line number information (-lineinfo) (requires cuda >= 5.5)- | Verbose -- ^ verbose log messages (requires cuda >= 5.5)- deriving (Show)---- |--- Results of online compilation----data JITResult = JITResult- {- jitTime :: !Float, -- ^ milliseconds spent compiling PTX- jitInfoLog :: !ByteString, -- ^ information about PTX assembly- jitModule :: !Module -- ^ the compiled module- }- deriving (Show)----- |--- Online compilation target architecture----{# enum CUjit_target as JITTarget- { underscoreToCase }- with prefix="CU_TARGET" deriving (Eq, Show) #}---- |--- Online compilation fallback strategy----{# enum CUjit_fallback as JITFallback- { underscoreToCase- , CU_PREFER_PTX as PreferPTX }- with prefix="CU" deriving (Eq, Show) #}---- |--- Device code formats that can be used for online linking----#if CUDA_VERSION < 5050-data JITInputType-#else-{# enum CUjitInputType as JITInputType- { underscoreToCase- , CU_JIT_INPUT_PTX as PTX }- with prefix="CU_JIT_INPUT" deriving (Eq, Show) #}-#endif--{# enum CUjit_option as JITOptionInternal- { }- with prefix="CU" deriving (Eq, Show) #}-------------------------------------------------------------------------------------- Module management------------------------------------------------------------------------------------- |--- Load the contents of the specified file (either a ptx or cubin file) to--- create a new module, and load that module into the current context.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g366093bd269dafd0af21f1c7d18115d3>----{-# INLINEABLE loadFile #-}-loadFile :: FilePath -> IO Module-loadFile !ptx = resultIfOk =<< cuModuleLoad ptx--{-# INLINE cuModuleLoad #-}-{# fun unsafe cuModuleLoad- { alloca- `Module' peekMod*- , withCString* `FilePath' } -> `Status' cToEnum #}----- |--- Load the contents of the given image into a new module, and load that module--- into the current context. The image is (typically) the contents of a cubin or--- PTX file.------ Note that the 'ByteString' will be copied into a temporary staging area so--- that it can be passed to C.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g04ce266ce03720f479eab76136b90c0b>----{-# INLINEABLE loadData #-}-loadData :: ByteString -> IO Module-loadData !img =- B.useAsCString img (\p -> loadDataFromPtr (castPtr p))---- |--- As 'loadData', but read the image data from the given pointer. The image is a--- NULL-terminated sequence of bytes.----{-# INLINEABLE loadDataFromPtr #-}-loadDataFromPtr :: Ptr Word8 -> IO Module-loadDataFromPtr !img = resultIfOk =<< cuModuleLoadData img--{-# INLINE cuModuleLoadData #-}-{# fun unsafe cuModuleLoadData- { alloca- `Module' peekMod*- , castPtr `Ptr Word8' } -> ` Status' cToEnum #}----- |--- Load the contents of the given image into a module with online compiler--- options, and load the module into the current context. The image is--- (typically) the contents of a cubin or PTX file. The actual attributes of the--- compiled kernel can be probed using 'requires'.------ Note that the 'ByteString' will be copied into a temporary staging area so--- that it can be passed to C.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g9e8047e9dbf725f0cd7cafd18bfd4d12>----{-# INLINEABLE loadDataEx #-}-loadDataEx :: ByteString -> [JITOption] -> IO JITResult-loadDataEx !img !options =- B.useAsCString img (\p -> loadDataFromPtrEx (castPtr p) options)---- |--- As 'loadDataEx', but read the image data from the given pointer. The image is--- a NULL-terminated sequence of bytes.----{-# INLINEABLE loadDataFromPtrEx #-}-loadDataFromPtrEx :: Ptr Word8 -> [JITOption] -> IO JITResult-loadDataFromPtrEx !img !options = do- let logSize = 2048-- fp_ilog <- B.mallocByteString logSize-- allocaArray logSize $ \p_elog -> do- withForeignPtr fp_ilog $ \p_ilog -> do-- let (opt,val) = unzip $- [ (JIT_WALL_TIME, 0) -- must be first, this is extracted below- , (JIT_INFO_LOG_BUFFER_SIZE_BYTES, logSize)- , (JIT_ERROR_LOG_BUFFER_SIZE_BYTES, logSize)- , (JIT_INFO_LOG_BUFFER, unsafeCoerce (p_ilog :: CString))- , (JIT_ERROR_LOG_BUFFER, unsafeCoerce (p_elog :: CString))- ]- ++- map jitOptionUnpack options-- withArrayLen (map cFromEnum opt) $ \i p_opts -> do- withArray (map unsafeCoerce val) $ \ p_vals -> do-- (s,mdl) <- cuModuleLoadDataEx img i p_opts p_vals-- case s of- Success -> do- time <- peek (castPtr p_vals)- bytes <- c_strnlen p_ilog logSize- let infoLog | bytes == 0 = B.empty- | otherwise = B.fromForeignPtr (castForeignPtr fp_ilog) 0 bytes- return $! JITResult time infoLog mdl-- _ -> do- errLog <- peekCString p_elog- cudaError (unlines [describe s, errLog])---{-# INLINE cuModuleLoadDataEx #-}-{# fun unsafe cuModuleLoadDataEx- { alloca- `Module' peekMod*- , castPtr `Ptr Word8'- , `Int'- , id `Ptr CInt'- , id `Ptr (Ptr ())' } -> `Status' cToEnum #}----- |--- Unload a module from the current context.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g8ea3d716524369de3763104ced4ea57b>----{-# INLINEABLE unload #-}-unload :: Module -> IO ()-unload !m = nothingIfOk =<< cuModuleUnload m--{-# INLINE cuModuleUnload #-}-{# fun unsafe cuModuleUnload- { useModule `Module' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------{-# INLINE peekMod #-}-peekMod :: Ptr {# type CUmodule #} -> IO Module-peekMod = liftM Module . peek---{-# INLINE jitOptionUnpack #-}-jitOptionUnpack :: JITOption -> (JITOptionInternal, Int)-jitOptionUnpack (MaxRegisters x) = (JIT_MAX_REGISTERS, x)-jitOptionUnpack (ThreadsPerBlock x) = (JIT_THREADS_PER_BLOCK, x)-jitOptionUnpack (OptimisationLevel x) = (JIT_OPTIMIZATION_LEVEL, x)-jitOptionUnpack (Target x) = (JIT_TARGET, fromEnum (jitTargetOfCompute x))-jitOptionUnpack (FallbackStrategy x) = (JIT_FALLBACK_STRATEGY, fromEnum x)-#if CUDA_VERSION >= 5050-jitOptionUnpack GenerateDebugInfo = (JIT_GENERATE_DEBUG_INFO, fromEnum True)-jitOptionUnpack GenerateLineInfo = (JIT_GENERATE_LINE_INFO, fromEnum True)-jitOptionUnpack Verbose = (JIT_LOG_VERBOSE, fromEnum True)-#else-jitOptionUnpack GenerateDebugInfo = requireSDK 'GenerateDebugInfo 5.5-jitOptionUnpack GenerateLineInfo = requireSDK 'GenerateLineInfo 5.5-jitOptionUnpack Verbose = requireSDK 'Verbose 5.5-#endif---{-# INLINE jitTargetOfCompute #-}-jitTargetOfCompute :: Compute -> JITTarget-jitTargetOfCompute (Compute 1 0) = Compute10-jitTargetOfCompute (Compute 1 1) = Compute11-jitTargetOfCompute (Compute 1 2) = Compute12-jitTargetOfCompute (Compute 1 3) = Compute13-jitTargetOfCompute (Compute 2 0) = Compute20-jitTargetOfCompute (Compute 2 1) = Compute21-#if CUDA_VERSION >= 5000-jitTargetOfCompute (Compute 3 0) = Compute30-jitTargetOfCompute (Compute 3 5) = Compute35-#endif-#if CUDA_VERSION >= 6000-jitTargetOfCompute (Compute 3 2) = Compute32-jitTargetOfCompute (Compute 5 0) = Compute50-#endif-#if CUDA_VERSION >= 6050-jitTargetOfCompute (Compute 3 7) = Compute37-#endif-#if CUDA_VERSION >= 7000-jitTargetOfCompute (Compute 5 2) = Compute52-#endif-jitTargetOfCompute compute = error ("Unknown JIT Target for Compute " ++ show compute)---#if defined(WIN32)-{-# INLINE c_strnlen' #-}-c_strnlen' :: CString -> CSize -> IO CSize-c_strnlen' str size = do- str' <- peekCStringLen (str, fromIntegral size)- return $ stringLen 0 str'- where- stringLen acc [] = acc- stringLen acc ('\0':_) = acc- stringLen acc (_:xs) = stringLen (acc+1) xs-#else-foreign import ccall unsafe "string.h strnlen" c_strnlen'- :: CString -> CSize -> IO CSize-#endif--{-# INLINE c_strnlen #-}-c_strnlen :: CString -> Int -> IO Int-c_strnlen str maxlen = cIntConv `fmap` c_strnlen' str (cIntConv maxlen)-
− Foreign/CUDA/Driver/Module/Link.chs
@@ -1,224 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Module.Link--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Module linking for low-level driver interface------ Since CUDA-5.5--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Module.Link (-- -- ** JIT module linking- LinkState, JITOption(..), JITInputType(..),-- create, destroy, complete,- addFile,- addData, addDataFromPtr,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Module.Base-import Foreign.CUDA.Internal.C2HS---- System-import Control.Monad ( liftM )-import Foreign-import Foreign.C-import Unsafe.Coerce--import Data.ByteString.Char8 ( ByteString )-import qualified Data.ByteString.Char8 as B-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A pending JIT linker state----#if CUDA_VERSION < 5050-data LinkState-#else-newtype LinkState = LinkState { useLinkState :: {# type CUlinkState #} }- deriving (Show)-#endif-------------------------------------------------------------------------------------- JIT linking------------------------------------------------------------------------------------- |--- Create a pending JIT linker invocation. The returned 'LinkState' should--- be 'destroy'ed once no longer needed. The device code machine size will--- match the calling application.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g86ca4052a2fab369cb943523908aa80d>----{-# INLINEABLE create #-}-create :: [JITOption] -> IO LinkState-#if CUDA_VERSION < 5050-create _ = requireSDK 'create 5.5-#else-create !options =- let (opt,val) = unzip $ map jitOptionUnpack options- in- withArray (map cFromEnum opt) $ \p_opts ->- withArray (map unsafeCoerce val) $ \p_vals ->- resultIfOk =<< cuLinkCreate (length opt) p_opts p_vals--{-# INLINE cuLinkCreate #-}-{# fun unsafe cuLinkCreate- { `Int'- , id `Ptr CInt'- , id `Ptr (Ptr ())'- , alloca- `LinkState' peekLS* } -> `Status' cToEnum #}- where- peekLS = liftM LinkState . peek-#endif----- |--- Destroy the state of a JIT linker invocation.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g01b7ae2a34047b05716969af245ce2d9>----{-# INLINEABLE destroy #-}-destroy :: LinkState -> IO ()-#if CUDA_VERSION < 5050-destroy _ = requireSDK 'destroy 5.5-#else-destroy !s = nothingIfOk =<< cuLinkDestroy s--{-# INLINE cuLinkDestroy #-}-{# fun unsafe cuLinkDestroy- { useLinkState `LinkState' } -> `Status' cToEnum #}-#endif----- |--- Complete a pending linker invocation and load the current module. The--- link state will be destroyed.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g818fcd84a4150a997c0bba76fef4e716>----{-# INLINEABLE complete #-}-complete :: LinkState -> IO Module-#if CUDA_VERSION < 5050-complete _ = requireSDK 'complete 5.5-#else-complete !ls = do- cubin <- resultIfOk =<< cuLinkComplete ls nullPtr- mdl <- loadDataFromPtr (castPtr cubin)- destroy ls- return mdl--{-# INLINE cuLinkComplete #-}-{# fun unsafe cuLinkComplete- { useLinkState `LinkState'- , alloca- `Ptr ()' peek*- , castPtr `Ptr Int'- }- -> `Status' cToEnum #}-#endif----- |--- Add an input file to a pending linker invocation.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g1224c0fd48d4a683f3ce19997f200a8c>----{-# INLINEABLE addFile #-}-addFile :: LinkState -> FilePath -> JITInputType -> [JITOption] -> IO ()-#if CUDA_VERSION < 5050-addFile _ _ _ _ = requireSDK 'addFile 5.5-#else-addFile !ls !fp !t !options =- let (opt,val) = unzip $ map jitOptionUnpack options- in- withArrayLen (map cFromEnum opt) $ \i p_opts ->- withArray (map unsafeCoerce val) $ \ p_vals ->- nothingIfOk =<< cuLinkAddFile ls t fp i p_opts p_vals--{-# INLINE cuLinkAddFile #-}-{# fun unsafe cuLinkAddFile- { useLinkState `LinkState'- , cFromEnum `JITInputType'- , withCString* `FilePath'- , `Int'- , id `Ptr CInt'- , id `Ptr (Ptr ())'- }- -> `Status' cToEnum #}-#endif----- |--- Add an input to a pending linker invocation.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g3ebcd2ccb772ba9c120937a2d2831b77>----{-# INLINEABLE addData #-}-addData :: LinkState -> ByteString -> JITInputType -> [JITOption] -> IO ()-#if CUDA_VERSION < 5050-addData _ _ _ = requireSDK 'addData 5.5-#else-addData !ls !img !k !options =- B.useAsCStringLen img (\(p, n) -> addDataFromPtr ls n (castPtr p) k options)-#endif---- |--- As 'addData', but read the specified number of bytes of image data from--- the given pointer.----{-# INLINEABLE addDataFromPtr #-}-addDataFromPtr :: LinkState -> Int -> Ptr Word8 -> JITInputType -> [JITOption] -> IO ()-#if CUDA_VERSION < 5050-addDataFromPtr _ _ _ _ = requireSDK 'addDataFromPtr 5.5-#else-addDataFromPtr !ls !n !img !t !options =- let (opt,val) = unzip $ map jitOptionUnpack options- in- withArrayLen (map cFromEnum opt) $ \i p_opts ->- withArray (map unsafeCoerce val) $ \ p_vals ->- nothingIfOk =<< cuLinkAddData ls t img n "<unknown>" i p_opts p_vals--{-# INLINE cuLinkAddData #-}-{# fun unsafe cuLinkAddData- { useLinkState `LinkState'- , cFromEnum `JITInputType'- , castPtr `Ptr Word8'- , `Int'- , `String'- , `Int'- , id `Ptr CInt'- , id `Ptr (Ptr ())'- }- -> `Status' cToEnum #}-#endif-
− Foreign/CUDA/Driver/Module/Query.chs
@@ -1,108 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Module.Query--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Querying module attributes for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Module.Query (-- -- ** Querying module inhabitants- getFun, getPtr, getTex,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Exec-import Foreign.CUDA.Driver.Marshal ( peekDeviceHandle )-import Foreign.CUDA.Driver.Module.Base-import Foreign.CUDA.Driver.Texture-import Foreign.CUDA.Internal.C2HS-import Foreign.CUDA.Ptr---- System-import Foreign-import Foreign.C-import Control.Exception ( throwIO )-import Control.Monad ( liftM )-------------------------------------------------------------------------------------- Querying module attributes------------------------------------------------------------------------------------- |--- Returns a function handle.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1ga52be009b0d4045811b30c965e1cb2cf>----{-# INLINEABLE getFun #-}-getFun :: Module -> String -> IO Fun-getFun !mdl !fn = resultIfFound "function" fn =<< cuModuleGetFunction mdl fn--{-# INLINE cuModuleGetFunction #-}-{# fun unsafe cuModuleGetFunction- { alloca- `Fun' peekFun*- , useModule `Module'- , withCString* `String' } -> `Status' cToEnum #}- where peekFun = liftM Fun . peek----- |--- Return a global pointer, and size of the global (in bytes).------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1gf3e43672e26073b1081476dbf47a86ab>----{-# INLINEABLE getPtr #-}-getPtr :: Module -> String -> IO (DevicePtr a, Int)-getPtr !mdl !name = do- (!status,!dptr,!bytes) <- cuModuleGetGlobal mdl name- resultIfFound "global" name (status,(dptr,bytes))--{-# INLINE cuModuleGetGlobal #-}-{# fun unsafe cuModuleGetGlobal- { alloca- `DevicePtr a' peekDeviceHandle*- , alloca- `Int' peekIntConv*- , useModule `Module'- , withCString* `String' } -> `Status' cToEnum #}----- |--- Return a handle to a texture reference. This texture reference handle--- should not be destroyed, as the texture will be destroyed automatically--- when the module is unloaded.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g9607dcbf911c16420d5264273f2b5608>----{-# INLINEABLE getTex #-}-getTex :: Module -> String -> IO Texture-getTex !mdl !name = resultIfFound "texture" name =<< cuModuleGetTexRef mdl name--{-# INLINE cuModuleGetTexRef #-}-{# fun unsafe cuModuleGetTexRef- { alloca- `Texture' peekTex*- , useModule `Module'- , withCString* `String' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------{-# INLINE resultIfFound #-}-resultIfFound :: String -> String -> (Status, a) -> IO a-resultIfFound kind name (!status,!result) =- case status of- Success -> return result- NotFound -> cudaError (kind ++ ' ' : describe status ++ ": " ++ name)- _ -> throwIO (ExitCode status)-
− Foreign/CUDA/Driver/Profiler.chs
@@ -1,100 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Profiler--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Profiler control for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Profiler (-- OutputMode(..),- initialise,- start, stop,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- friends-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- system-import Foreign-import Foreign.C----- | Profiler output mode----{# enum CUoutput_mode as OutputMode- { underscoreToCase- , CU_OUT_CSV as CSV }- with prefix="CU_OUT" deriving (Eq, Show) #}----- | Initialise the CUDA profiler.------ The configuration file is used to specify profiling options and profiling--- counters. Refer to the "Compute Command Line Profiler User Guide" for--- supported profiler options and counters.------ Note that the CUDA profiler can not be initialised with this function if--- another profiling tool is already active.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER>----{-# INLINEABLE initialise #-}-initialise- :: FilePath -- ^ configuration file that itemises which counters and/or options to profile- -> FilePath -- ^ output file where profiling results will be stored- -> OutputMode- -> IO ()-initialise config output mode- = nothingIfOk =<< cuProfilerInitialize config output mode--{-# INLINE cuProfilerInitialize #-}-{# fun unsafe cuProfilerInitialize- { `String'- , `String'- , cFromEnum `OutputMode'- }- -> `Status' cToEnum #}----- | Begin profiling collection by the active profiling tool for the current--- context. If profiling is already enabled, then this has no effect.------ 'start' and 'stop' can be used to programatically control profiling--- granularity, by allowing profiling to be done only on selected pieces of--- code.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER_1g8a5314de2292c2efac83ac7fcfa9190e>----{-# INLINEABLE start #-}-start :: IO ()-start = nothingIfOk =<< cuProfilerStart--{-# INLINE cuProfilerStart #-}-{# fun unsafe cuProfilerStart- { } -> `Status' cToEnum #}----- | Stop profiling collection by the active profiling tool for the current--- context, and force all pending profiler events to be written to the output--- file. If profiling is already inactive, this has no effect.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER_1g4d8edef6174fd90165e6ac838f320a5f>----{-# INLINEABLE stop #-}-stop :: IO ()-stop = nothingIfOk =<< cuProfilerStop--{-# INLINE cuProfilerStop #-}-{# fun unsafe cuProfilerStop- { } -> `Status' cToEnum #}-
− Foreign/CUDA/Driver/Stream.chs
@@ -1,167 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Stream--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Stream management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Stream (-- -- * Stream Management- Stream(..), StreamFlag,- create, createWithPriority, destroy, finished, block, getPriority,-- defaultStream,--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Types-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad ( liftM )-import Control.Exception ( throwIO )-------------------------------------------------------------------------------------- Stream management------------------------------------------------------------------------------------- |--- Create a new stream.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1ga581f0c5833e21ded8b5a56594e243f4>----{-# INLINEABLE create #-}-create :: [StreamFlag] -> IO Stream-create !flags = resultIfOk =<< cuStreamCreate flags--{-# INLINE cuStreamCreate #-}-{# fun unsafe cuStreamCreate- { alloca- `Stream' peekStream*- , combineBitMasks `[StreamFlag]' } -> `Status' cToEnum #}- where- peekStream = liftM Stream . peek----- |--- Create a stream with the given priority. Work submitted to--- a higher-priority stream may preempt work already executing in a lower--- priority stream.------ The convention is that lower numbers represent higher priorities. The--- default priority is zero. The range of meaningful numeric priorities can--- be queried using 'Foreign.CUDA.Driver.Context.Config.getStreamPriorityRange'.--- If the specified priority is outside the supported numerical range, it--- will automatically be clamped to the highest or lowest number in the--- range.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g95c1a8c7c3dacb13091692dd9c7f7471>----{-# INLINEABLE createWithPriority #-}-createWithPriority :: StreamPriority -> [StreamFlag] -> IO Stream-#if CUDA_VERSION < 5050-createWithPriority _ _ = requireSDK 'createWithPriority 5.5-#else-createWithPriority !priority !flags = resultIfOk =<< cuStreamCreateWithPriority flags priority--{-# INLINE cuStreamCreateWithPriority #-}-{# fun unsafe cuStreamCreateWithPriority- { alloca- `Stream' peekStream*- , combineBitMasks `[StreamFlag]'- , cIntConv `StreamPriority'- }- -> `Status' cToEnum #}- where- peekStream = liftM Stream . peek-#endif----- |--- Destroy a stream. If the device is still doing work in the stream when--- 'destroy' is called, the function returns immediately and the resources--- associated with the stream will be released automatically once the--- device has completed all work.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g244c8833de4596bcd31a06cdf21ee758>----{-# INLINEABLE destroy #-}-destroy :: Stream -> IO ()-destroy !st = nothingIfOk =<< cuStreamDestroy st--{-# INLINE cuStreamDestroy #-}-{# fun unsafe cuStreamDestroy- { useStream `Stream' } -> `Status' cToEnum #}----- |--- Check if all operations in the stream have completed.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g1b0d24bbe97fa68e4bc511fb6adfeb0b>----{-# INLINEABLE finished #-}-finished :: Stream -> IO Bool-finished !st =- cuStreamQuery st >>= \rv ->- case rv of- Success -> return True- NotReady -> return False- _ -> throwIO (ExitCode rv)--{-# INLINE cuStreamQuery #-}-{# fun unsafe cuStreamQuery- { useStream `Stream' } -> `Status' cToEnum #}----- |--- Wait until the device has completed all operations in the Stream.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g15e49dd91ec15991eb7c0a741beb7dad>----{-# INLINEABLE block #-}-block :: Stream -> IO ()-block !st = nothingIfOk =<< cuStreamSynchronize st--{-# INLINE cuStreamSynchronize #-}-{# fun cuStreamSynchronize- { useStream `Stream' } -> `Status' cToEnum #}----- |--- Query the priority of a stream.------ Requires CUDA-5.5.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g5bd5cb26915a2ecf1921807339488484>----{-# INLINEABLE getPriority #-}-getPriority :: Stream -> IO StreamPriority-#if CUDA_VERSION < 5050-getPriority _ = requireSDK 'getPriority 5.5-#else-getPriority !st = resultIfOk =<< cuStreamGetPriority st--{-# INLINE cuStreamGetPriority #-}-{# fun unsafe cuStreamGetPriority- { useStream `Stream'- , alloca- `StreamPriority' peekIntConv*- }- -> `Status' cToEnum #}-#endif-
− Foreign/CUDA/Driver/Texture.chs
@@ -1,308 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# OPTIONS_HADDOCK prune #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Texture--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Texture management for low-level driver interface--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Texture (-- -- * Texture Reference Management- Texture(..), Format(..), AddressMode(..), FilterMode(..), ReadMode(..),- bind, bind2D,- getAddressMode, getFilterMode, getFormat,- setAddressMode, setFilterMode, setFormat, setReadMode,-- -- Deprecated- create, destroy,-- -- Internal- peekTex--) where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Ptr-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Driver.Marshal-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad--#if CUDA_VERSION >= 3020-{-# DEPRECATED create, destroy "as of CUDA version 3.2" #-}-#endif-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A texture reference----newtype Texture = Texture { useTexture :: {# type CUtexref #}}- deriving (Eq, Show)--instance Storable Texture where- sizeOf _ = sizeOf (undefined :: {# type CUtexref #})- alignment _ = alignment (undefined :: {# type CUtexref #})- peek p = Texture `fmap` peek (castPtr p)- poke p t = poke (castPtr p) (useTexture t)---- |--- Texture reference addressing modes----{# enum CUaddress_mode as AddressMode- { underscoreToCase }- with prefix="CU_TR_ADDRESS_MODE" deriving (Eq, Show) #}---- |--- Texture reference filtering mode----{# enum CUfilter_mode as FilterMode- { underscoreToCase }- with prefix="CU_TR_FILTER_MODE" deriving (Eq, Show) #}---- |--- Texture read mode options----#c-typedef enum CUtexture_flag_enum {- CU_TEXTURE_FLAG_READ_AS_INTEGER = CU_TRSF_READ_AS_INTEGER,- CU_TEXTURE_FLAG_NORMALIZED_COORDINATES = CU_TRSF_NORMALIZED_COORDINATES,- CU_TEXTURE_FLAG_SRGB = CU_TRSF_SRGB-} CUtexture_flag;-#endc--{# enum CUtexture_flag as ReadMode- { underscoreToCase- , CU_TEXTURE_FLAG_SRGB as SRGB }- with prefix="CU_TEXTURE_FLAG" deriving (Eq, Show) #}---- |--- Texture data formats----{# enum CUarray_format as Format- { underscoreToCase- , UNSIGNED_INT8 as Word8- , UNSIGNED_INT16 as Word16- , UNSIGNED_INT32 as Word32- , SIGNED_INT8 as Int8- , SIGNED_INT16 as Int16- , SIGNED_INT32 as Int32 }- with prefix="CU_AD_FORMAT" deriving (Eq, Show) #}-------------------------------------------------------------------------------------- Texture management------------------------------------------------------------------------------------- |--- Create a new texture reference. Once created, the application must call--- 'setPtr' to associate the reference with allocated memory. Other texture--- reference functions are used to specify the format and interpretation to be--- used when the memory is read through this reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF__DEPRECATED.html#group__CUDA__TEXREF__DEPRECATED_1g0084fabe2c6d28ffcf9d9f5c7164f16c>----{-# INLINEABLE create #-}-create :: IO Texture-create = resultIfOk =<< cuTexRefCreate--{-# INLINE cuTexRefCreate #-}-{# fun unsafe cuTexRefCreate- { alloca- `Texture' peekTex* } -> `Status' cToEnum #}----- |--- Destroy a texture reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF__DEPRECATED.html#group__CUDA__TEXREF__DEPRECATED_1gea8edbd6cf9f97e6ab2b41fc6785519d>----{-# INLINEABLE destroy #-}-destroy :: Texture -> IO ()-destroy !tex = nothingIfOk =<< cuTexRefDestroy tex--{-# INLINE cuTexRefDestroy #-}-{# fun unsafe cuTexRefDestroy- { useTexture `Texture' } -> `Status' cToEnum #}----- |--- Bind a linear array address of the given size (bytes) as a texture--- reference. Any previously bound references are unbound.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g44ef7e5055192d52b3d43456602b50a8>----{-# INLINEABLE bind #-}-bind :: Texture -> DevicePtr a -> Int64 -> IO ()-bind !tex !dptr !bytes = nothingIfOk =<< cuTexRefSetAddress tex dptr bytes--{-# INLINE cuTexRefSetAddress #-}-{# fun unsafe cuTexRefSetAddress- { alloca- `Int'- , useTexture `Texture'- , useDeviceHandle `DevicePtr a'- , `Int64' } -> `Status' cToEnum #}----- |--- Bind a linear address range to the given texture reference as a--- two-dimensional arena. Any previously bound reference is unbound. Note that--- calls to 'setFormat' can not follow a call to 'bind2D' for the same texture--- reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g26f709bbe10516681913d1ffe8756ee2>----{-# INLINEABLE bind2D #-}-bind2D :: Texture -> Format -> Int -> DevicePtr a -> (Int,Int) -> Int64 -> IO ()-bind2D !tex !fmt !chn !dptr (!width,!height) !pitch =- nothingIfOk =<< cuTexRefSetAddress2DSimple tex fmt chn dptr width height pitch--{-# INLINE cuTexRefSetAddress2DSimple #-}-{# fun unsafe cuTexRefSetAddress2DSimple- { useTexture `Texture'- , cFromEnum `Format'- , `Int'- , useDeviceHandle `DevicePtr a'- , `Int'- , `Int'- , `Int64' } -> `Status' cToEnum #}----- |--- Get the addressing mode used by a texture reference, corresponding to the--- given dimension (currently the only supported dimension values are 0 or 1).------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1gfb367d93dc1d20aab0cf8ce70d543b33>----{-# INLINEABLE getAddressMode #-}-getAddressMode :: Texture -> Int -> IO AddressMode-getAddressMode !tex !dim = resultIfOk =<< cuTexRefGetAddressMode tex dim--{-# INLINE cuTexRefGetAddressMode #-}-{# fun unsafe cuTexRefGetAddressMode- { alloca- `AddressMode' peekEnum*- , useTexture `Texture'- , `Int' } -> `Status' cToEnum #}----- |--- Get the filtering mode used by a texture reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g2439e069746f69b940f2f4dbc78cdf87>----{-# INLINEABLE getFilterMode #-}-getFilterMode :: Texture -> IO FilterMode-getFilterMode !tex = resultIfOk =<< cuTexRefGetFilterMode tex--{-# INLINE cuTexRefGetFilterMode #-}-{# fun unsafe cuTexRefGetFilterMode- { alloca- `FilterMode' peekEnum*- , useTexture `Texture' } -> `Status' cToEnum #}----- |--- Get the data format and number of channel components of the bound texture.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g90936eb6c7c4434a609e1160c278ae53>----{-# INLINEABLE getFormat #-}-getFormat :: Texture -> IO (Format, Int)-getFormat !tex = do- (!status,!fmt,!dim) <- cuTexRefGetFormat tex- resultIfOk (status,(fmt,dim))--{-# INLINE cuTexRefGetFormat #-}-{# fun unsafe cuTexRefGetFormat- { alloca- `Format' peekEnum*- , alloca- `Int' peekIntConv*- , useTexture `Texture' } -> `Status' cToEnum #}----- |--- Specify the addressing mode for the given dimension of a texture reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g85f4a13eeb94c8072f61091489349bcb>----{-# INLINEABLE setAddressMode #-}-setAddressMode :: Texture -> Int -> AddressMode -> IO ()-setAddressMode !tex !dim !mode = nothingIfOk =<< cuTexRefSetAddressMode tex dim mode--{-# INLINE cuTexRefSetAddressMode #-}-{# fun unsafe cuTexRefSetAddressMode- { useTexture `Texture'- , `Int'- , cFromEnum `AddressMode' } -> `Status' cToEnum #}----- |--- Specify the filtering mode to be used when reading memory through a texture--- reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g595d0af02c55576f8c835e4efd1f39c0>----{-# INLINEABLE setFilterMode #-}-setFilterMode :: Texture -> FilterMode -> IO ()-setFilterMode !tex !mode = nothingIfOk =<< cuTexRefSetFilterMode tex mode--{-# INLINE cuTexRefSetFilterMode #-}-{# fun unsafe cuTexRefSetFilterMode- { useTexture `Texture'- , cFromEnum `FilterMode' } -> `Status' cToEnum #}----- |--- Specify additional characteristics for reading and indexing the texture--- reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g554ffd896487533c36810f2e45bb7a28>----{-# INLINEABLE setReadMode #-}-setReadMode :: Texture -> ReadMode -> IO ()-setReadMode !tex !mode = nothingIfOk =<< cuTexRefSetFlags tex mode--{-# INLINE cuTexRefSetFlags #-}-{# fun unsafe cuTexRefSetFlags- { useTexture `Texture'- , cFromEnum `ReadMode' } -> `Status' cToEnum #}----- |--- Specify the format of the data and number of packed components per element to--- be read by the texture reference.------ <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g05585ef8ea2fec728a03c6c8f87cf07a>----{-# INLINEABLE setFormat #-}-setFormat :: Texture -> Format -> Int -> IO ()-setFormat !tex !fmt !chn = nothingIfOk =<< cuTexRefSetFormat tex fmt chn--{-# INLINE cuTexRefSetFormat #-}-{# fun unsafe cuTexRefSetFormat- { useTexture `Texture'- , cFromEnum `Format'- , `Int' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------{-# INLINE peekTex #-}-peekTex :: Ptr {# type CUtexref #} -> IO Texture-peekTex = liftM Texture . peek-
− Foreign/CUDA/Driver/Utils.chs
@@ -1,37 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Utils--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Utility functions--------------------------------------------------------------------------------------module Foreign.CUDA.Driver.Utils (driverVersion)- where--#include "cbits/stubs.h"-{# context lib="cuda" #}---- Friends-import Foreign.CUDA.Driver.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C----- |--- Return the version number of the installed CUDA driver.----{-# INLINEABLE driverVersion #-}-driverVersion :: IO Int-driverVersion = resultIfOk =<< cuDriverGetVersion--{-# INLINE cuDriverGetVersion #-}-{# fun unsafe cuDriverGetVersion- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}-
− Foreign/CUDA/Internal/C2HS.hs
@@ -1,230 +0,0 @@--- C->Haskell Compiler: Marshalling library------ Copyright (c) [1999...2005] Manuel M T Chakravarty------ Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are met:------ 1. Redistributions of source code must retain the above copyright notice,--- this list of conditions and the following disclaimer.--- 2. Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- 3. The name of the author may not be used to endorse or promote products--- derived from this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR--- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES--- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN--- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,--- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED--- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.------- Description --------------------------------------------------------------------- Language: Haskell 98------ This module provides the marshaling routines for Haskell files produced by--- C->Haskell for binding to C library interfaces. It exports all of the--- low-level FFI (language-independent plus the C-specific parts) together--- with the C->HS-specific higher-level marshalling routines.-----module Foreign.CUDA.Internal.C2HS (-- -- * Composite marshalling functions- withCStringLenIntConv, peekCStringLenIntConv, withIntConv, withFloatConv,- peekIntConv, peekFloatConv, withBool, peekBool, withEnum, peekEnum,- peekArrayWith,-- -- * Conditional results using 'Maybe'- nothingIf, nothingIfNull,-- -- * Bit masks- combineBitMasks, containsBitMask, extractBitMasks,-- -- * Conversion between C and Haskell types- cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum-) where---import Foreign-import Foreign.C-import Control.Monad ( liftM )----- Composite marshalling functions--- ----------------------------------- Strings with explicit length----withCStringLenIntConv :: String -> (CStringLen -> IO a) -> IO a-withCStringLenIntConv s f = withCStringLen s $ \(p, n) -> f (p, cIntConv n)--peekCStringLenIntConv :: CStringLen -> IO String-peekCStringLenIntConv (s, n) = peekCStringLen (s, cIntConv n)---- Marshalling of numerals-----withIntConv :: (Storable b, Integral a, Integral b) => a -> (Ptr b -> IO c) -> IO c-withIntConv = with . cIntConv--withFloatConv :: (Storable b, RealFloat a, RealFloat b) => a -> (Ptr b -> IO c) -> IO c-withFloatConv = with . cFloatConv--peekIntConv :: (Storable a, Integral a, Integral b) => Ptr a -> IO b-peekIntConv = liftM cIntConv . peek--peekFloatConv :: (Storable a, RealFloat a, RealFloat b) => Ptr a -> IO b-peekFloatConv = liftM cFloatConv . peek---- Passing Booleans by reference-----withBool :: (Integral a, Storable a) => Bool -> (Ptr a -> IO b) -> IO b-withBool = with . fromBool--peekBool :: (Integral a, Storable a) => Ptr a -> IO Bool-peekBool = liftM toBool . peek----- Read and marshal array elements-----peekArrayWith :: Storable a => (a -> b) -> Int -> Ptr a -> IO [b]-peekArrayWith f n p = map f `fmap` peekArray n p----- Passing enums by reference-----withEnum :: (Enum a, Integral b, Storable b) => a -> (Ptr b -> IO c) -> IO c-withEnum = with . cFromEnum--peekEnum :: (Enum a, Integral b, Storable b) => Ptr b -> IO a-peekEnum = liftM cToEnum . peek---{---- Storing of 'Maybe' values--- ---------------------------instance Storable a => Storable (Maybe a) where- sizeOf _ = sizeOf (undefined :: Ptr ())- alignment _ = alignment (undefined :: Ptr ())-- peek p = do- ptr <- peek (castPtr p)- if ptr == nullPtr- then return Nothing- else liftM Just $ peek ptr-- poke p v = do- ptr <- case v of- Nothing -> return nullPtr- Just v' -> new v'- poke (castPtr p) ptr--}----- Conditional results using 'Maybe'--- ------------------------------------- Wrap the result into a 'Maybe' type.------ * the predicate determines when the result is considered to be non-existing,--- ie, it is represented by `Nothing'------ * the second argument allows to map a result wrapped into `Just' to some--- other domain----nothingIf :: (a -> Bool) -> (a -> b) -> a -> Maybe b-nothingIf p f x = if p x then Nothing else Just $ f x---- |Instance for special casing null pointers.----nothingIfNull :: (Ptr a -> b) -> Ptr a -> Maybe b-nothingIfNull = nothingIf (== nullPtr)----- Support for bit masks--- ------------------------- Given a list of enumeration values that represent bit masks, combine these--- masks using bitwise disjunction.----combineBitMasks :: (Enum a, Num b, Bits b) => [a] -> b-combineBitMasks = foldl (.|.) 0 . map (fromIntegral . fromEnum)---- Tests whether the given bit mask is contained in the given bit pattern--- (i.e., all bits set in the mask are also set in the pattern).----containsBitMask :: (Num a, Bits a, Enum b) => a -> b -> Bool-bits `containsBitMask` bm = let bm' = fromIntegral . fromEnum $ bm- in- bm' .&. bits == bm'---- |Given a bit pattern, yield all bit masks that it contains.------ * This does *not* attempt to compute a minimal set of bit masks that when--- combined yield the bit pattern, instead all contained bit masks are--- produced.----extractBitMasks :: (Num a, Bits a, Enum b, Bounded b) => a -> [b]-extractBitMasks bits =- [bm | bm <- [minBound..maxBound], bits `containsBitMask` bm]----- Conversion routines--- ----------------------- |Integral conversion----{-# INLINE [1] cIntConv #-}-cIntConv :: (Integral a, Integral b) => a -> b-cIntConv = fromIntegral---- |Floating conversion----{-# INLINE [1] cFloatConv #-}-cFloatConv :: (RealFloat a, RealFloat b) => a -> b-cFloatConv = realToFrac--- As this conversion by default goes via `Rational', it can be very slow...-{-# RULES- "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;- "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x;- "cFloatConv/Float->CFloat" forall (x::Float). cFloatConv x = CFloat x;- "cFloatConv/CFloat->Float" forall (x::Float). cFloatConv CFloat x = x;- "cFloatConv/Double->CDouble" forall (x::Double). cFloatConv x = CDouble x;- "cFloatConv/CDouble->Double" forall (x::Double). cFloatConv CDouble x = x- #-}---- |Obtain C value from Haskell 'Bool'.----{-# INLINE [1] cFromBool #-}-cFromBool :: Num a => Bool -> a-cFromBool = fromBool---- |Obtain Haskell 'Bool' from C value.----{-# INLINE [1] cToBool #-}-cToBool :: (Eq a, Num a) => a -> Bool-cToBool = toBool---- |Convert a C enumeration to Haskell.----{-# INLINE [1] cToEnum #-}-cToEnum :: (Integral i, Enum e) => i -> e-cToEnum = toEnum . cIntConv---- |Convert a Haskell enumeration to C.----{-# INLINE [1] cFromEnum #-}-cFromEnum :: (Enum e, Integral i) => e -> i-cFromEnum = cIntConv . fromEnum-
− Foreign/CUDA/Ptr.hs
@@ -1,184 +0,0 @@-{-# LANGUAGE BangPatterns #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Ptr--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Data pointers on the host and device. These can be shared freely between the--- CUDA runtime and Driver APIs.--------------------------------------------------------------------------------------module Foreign.CUDA.Ptr (-- -- * Device pointers- DevicePtr(..),- withDevicePtr,- devPtrToWordPtr,- wordPtrToDevPtr,- nullDevPtr,- castDevPtr,- plusDevPtr,- alignDevPtr,- minusDevPtr,- advanceDevPtr,-- -- * Host pointers- HostPtr(..),- withHostPtr,- nullHostPtr,- castHostPtr,- plusHostPtr,- alignHostPtr,- minusHostPtr,- advanceHostPtr,--) where---- friends-import Foreign.CUDA.Types---- system-import Foreign.Ptr-import Foreign.Storable-------------------------------------------------------------------------------------- Device Pointer------------------------------------------------------------------------------------- |--- Look at the contents of device memory. This takes an IO action that will be--- applied to that pointer, the result of which is returned. It would be silly--- to return the pointer from the action.----{-# INLINEABLE withDevicePtr #-}-withDevicePtr :: DevicePtr a -> (Ptr a -> IO b) -> IO b-withDevicePtr !p !f = f (useDevicePtr p)---- |--- Return a unique handle associated with the given device pointer----{-# INLINEABLE devPtrToWordPtr #-}-devPtrToWordPtr :: DevicePtr a -> WordPtr-devPtrToWordPtr = ptrToWordPtr . useDevicePtr---- |--- Return a device pointer from the given handle----{-# INLINEABLE wordPtrToDevPtr #-}-wordPtrToDevPtr :: WordPtr -> DevicePtr a-wordPtrToDevPtr = DevicePtr . wordPtrToPtr---- |--- The constant 'nullDevPtr' contains the distinguished memory location that is--- not associated with a valid memory location----{-# INLINEABLE nullDevPtr #-}-nullDevPtr :: DevicePtr a-nullDevPtr = DevicePtr nullPtr---- |--- Cast a device pointer from one type to another----{-# INLINEABLE castDevPtr #-}-castDevPtr :: DevicePtr a -> DevicePtr b-castDevPtr (DevicePtr !p) = DevicePtr (castPtr p)---- |--- Advance the pointer address by the given offset in bytes.----{-# INLINEABLE plusDevPtr #-}-plusDevPtr :: DevicePtr a -> Int -> DevicePtr a-plusDevPtr (DevicePtr !p) !d = DevicePtr (p `plusPtr` d)---- |--- Given an alignment constraint, align the device pointer to the next highest--- address satisfying the constraint----{-# INLINEABLE alignDevPtr #-}-alignDevPtr :: DevicePtr a -> Int -> DevicePtr a-alignDevPtr (DevicePtr !p) !i = DevicePtr (p `alignPtr` i)---- |--- Compute the difference between the second and first argument. This fulfils--- the relation------ > p2 == p1 `plusDevPtr` (p2 `minusDevPtr` p1)----{-# INLINEABLE minusDevPtr #-}-minusDevPtr :: DevicePtr a -> DevicePtr a -> Int-minusDevPtr (DevicePtr !a) (DevicePtr !b) = a `minusPtr` b---- |--- Advance a pointer into a device array by the given number of elements----{-# INLINEABLE advanceDevPtr #-}-advanceDevPtr :: Storable a => DevicePtr a -> Int -> DevicePtr a-advanceDevPtr = doAdvance undefined- where- doAdvance :: Storable a' => a' -> DevicePtr a' -> Int -> DevicePtr a'- doAdvance x !p !i = p `plusDevPtr` (i * sizeOf x)-------------------------------------------------------------------------------------- Host Pointer------------------------------------------------------------------------------------- |--- Apply an IO action to the memory reference living inside the host pointer--- object. All uses of the pointer should be inside the 'withHostPtr' bracket.----{-# INLINEABLE withHostPtr #-}-withHostPtr :: HostPtr a -> (Ptr a -> IO b) -> IO b-withHostPtr !p !f = f (useHostPtr p)----- |--- The constant 'nullHostPtr' contains the distinguished memory location that is--- not associated with a valid memory location----{-# INLINEABLE nullHostPtr #-}-nullHostPtr :: HostPtr a-nullHostPtr = HostPtr nullPtr---- |--- Cast a host pointer from one type to another----{-# INLINEABLE castHostPtr #-}-castHostPtr :: HostPtr a -> HostPtr b-castHostPtr (HostPtr !p) = HostPtr (castPtr p)---- |--- Advance the pointer address by the given offset in bytes----{-# INLINEABLE plusHostPtr #-}-plusHostPtr :: HostPtr a -> Int -> HostPtr a-plusHostPtr (HostPtr !p) !d = HostPtr (p `plusPtr` d)---- |--- Given an alignment constraint, align the host pointer to the next highest--- address satisfying the constraint----{-# INLINEABLE alignHostPtr #-}-alignHostPtr :: HostPtr a -> Int -> HostPtr a-alignHostPtr (HostPtr !p) !i = HostPtr (p `alignPtr` i)---- |--- Compute the difference between the second and first argument----{-# INLINEABLE minusHostPtr #-}-minusHostPtr :: HostPtr a -> HostPtr a -> Int-minusHostPtr (HostPtr !a) (HostPtr !b) = a `minusPtr` b---- |--- Advance a pointer into a host array by a given number of elements----{-# INLINEABLE advanceHostPtr #-}-advanceHostPtr :: Storable a => HostPtr a -> Int -> HostPtr a-advanceHostPtr = doAdvance undefined- where- doAdvance :: Storable a' => a' -> HostPtr a' -> Int -> HostPtr a'- doAdvance x !p !i = p `plusHostPtr` (i * sizeOf x)-
− Foreign/CUDA/Runtime.hs
@@ -1,28 +0,0 @@------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Top level bindings to the C-for-CUDA runtime API--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime (-- module Foreign.CUDA.Ptr,- module Foreign.CUDA.Runtime.Device,- module Foreign.CUDA.Runtime.Error,- module Foreign.CUDA.Runtime.Exec,- module Foreign.CUDA.Runtime.Marshal,- module Foreign.CUDA.Runtime.Utils--) where--import Foreign.CUDA.Ptr-import Foreign.CUDA.Runtime.Device-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Runtime.Exec-import Foreign.CUDA.Runtime.Marshal-import Foreign.CUDA.Runtime.Utils-
− Foreign/CUDA/Runtime/Device.chs
@@ -1,464 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Device--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Device management routines--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Device (-- -- * Device Management- Device, DeviceFlag(..), DeviceProperties(..), Compute(..), ComputeMode(..),- choose, get, count, props, set, setFlags, setOrder, reset, sync,-- -- * Peer Access- PeerFlag,- accessible, add, remove,-- -- * Cache Configuration- Limit(..),- getLimit, setLimit--) where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Analysis.Device-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C--#c-typedef struct cudaDeviceProp cudaDeviceProp;--typedef enum-{- cudaDeviceFlagScheduleAuto = cudaDeviceScheduleAuto,- cudaDeviceFlagScheduleSpin = cudaDeviceScheduleSpin,- cudaDeviceFlagScheduleYield = cudaDeviceScheduleYield,- cudaDeviceFlagBlockingSync = cudaDeviceBlockingSync,- cudaDeviceFlagMapHost = cudaDeviceMapHost,-#if CUDART_VERSION >= 3000- cudaDeviceFlagLMemResizeToMax = cudaDeviceLmemResizeToMax-#endif-} cudaDeviceFlags;-#endc-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A device identifier----type Device = Int--{# pointer *cudaDeviceProp as ^ foreign -> DeviceProperties nocode #}---- |--- Device execution flags----{# enum cudaDeviceFlags as DeviceFlag { }- with prefix="cudaDeviceFlag" deriving (Eq, Show, Bounded) #}---instance Storable DeviceProperties where- sizeOf _ = {#sizeof cudaDeviceProp#}- alignment _ = alignment (undefined :: Ptr ())-- poke _ _ = error "no instance for Foreign.Storable.poke DeviceProperties"- peek p = do- n <- peekCString =<< {#get cudaDeviceProp.name#} p- gm <- cIntConv `fmap` {#get cudaDeviceProp.totalGlobalMem#} p- sm <- cIntConv `fmap` {#get cudaDeviceProp.sharedMemPerBlock#} p- rb <- cIntConv `fmap` {#get cudaDeviceProp.regsPerBlock#} p- ws <- cIntConv `fmap` {#get cudaDeviceProp.warpSize#} p- mp <- cIntConv `fmap` {#get cudaDeviceProp.memPitch#} p- tb <- cIntConv `fmap` {#get cudaDeviceProp.maxThreadsPerBlock#} p- cl <- cIntConv `fmap` {#get cudaDeviceProp.clockRate#} p- cm <- cIntConv `fmap` {#get cudaDeviceProp.totalConstMem#} p- v1 <- fromIntegral `fmap` {#get cudaDeviceProp.major#} p- v2 <- fromIntegral `fmap` {#get cudaDeviceProp.minor#} p- ta <- cIntConv `fmap` {#get cudaDeviceProp.textureAlignment#} p- ov <- cToBool `fmap` {#get cudaDeviceProp.deviceOverlap#} p- pc <- cIntConv `fmap` {#get cudaDeviceProp.multiProcessorCount#} p- ke <- cToBool `fmap` {#get cudaDeviceProp.kernelExecTimeoutEnabled#} p- tg <- cToBool `fmap` {#get cudaDeviceProp.integrated#} p- hm <- cToBool `fmap` {#get cudaDeviceProp.canMapHostMemory#} p- md <- cToEnum `fmap` {#get cudaDeviceProp.computeMode#} p-#if CUDART_VERSION >= 3000- ck <- cToBool `fmap` {#get cudaDeviceProp.concurrentKernels#} p- u1 <- cIntConv `fmap` {#get cudaDeviceProp.maxTexture1D#} p-#endif-#if CUDART_VERSION >= 3010- ee <- cToBool `fmap` {#get cudaDeviceProp.ECCEnabled#} p-#endif-#if CUDART_VERSION >= 4000- ae <- cIntConv `fmap` {#get cudaDeviceProp.asyncEngineCount#} p- l2 <- cIntConv `fmap` {#get cudaDeviceProp.l2CacheSize#} p- tm <- cIntConv `fmap` {#get cudaDeviceProp.maxThreadsPerMultiProcessor#} p- mw <- cIntConv `fmap` {#get cudaDeviceProp.memoryBusWidth#} p- mc <- cIntConv `fmap` {#get cudaDeviceProp.memoryClockRate#} p- pb <- cIntConv `fmap` {#get cudaDeviceProp.pciBusID#} p- pd <- cIntConv `fmap` {#get cudaDeviceProp.pciDeviceID#} p- pm <- cIntConv `fmap` {#get cudaDeviceProp.pciDomainID#} p- tc <- cToBool `fmap` {#get cudaDeviceProp.tccDriver#} p- ua <- cToBool `fmap` {#get cudaDeviceProp.unifiedAddressing#} p-#endif- [t1,t2,t3] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxThreadsDim#} p- [g1,g2,g3] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxGridSize#} p-#if CUDART_VERSION >= 3000- [u21,u22] <- peekArrayWith cIntConv 2 =<< {#get cudaDeviceProp.maxTexture2D#} p- [u31,u32,u33] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxTexture3D#} p-#endif-#if CUDART_VERSION >= 5050- sp <- cToBool `fmap` {#get cudaDeviceProp.streamPrioritiesSupported#} p-#endif-#if CUDART_VERSION >= 6000- gl1 <- cToBool `fmap` {#get cudaDeviceProp.globalL1CacheSupported#} p- ll1 <- cToBool `fmap` {#get cudaDeviceProp.localL1CacheSupported#} p- mm <- cToBool `fmap` {#get cudaDeviceProp.managedMemory#} p- mg <- cToBool `fmap` {#get cudaDeviceProp.isMultiGpuBoard#} p- mid <- cIntConv `fmap` {#get cudaDeviceProp.multiGpuBoardGroupID#} p-#endif-- return DeviceProperties- {- deviceName = n- , computeCapability = Compute v1 v2- , totalGlobalMem = gm- , totalConstMem = cm- , sharedMemPerBlock = sm- , regsPerBlock = rb- , warpSize = ws- , maxThreadsPerBlock = tb- , maxBlockSize = (t1,t2,t3)- , maxGridSize = (g1,g2,g3)- , clockRate = cl- , multiProcessorCount = pc- , memPitch = mp- , textureAlignment = ta- , computeMode = md- , deviceOverlap = ov- , kernelExecTimeoutEnabled = ke- , integrated = tg- , canMapHostMemory = hm-#if CUDART_VERSION >= 3000- , concurrentKernels = ck- , maxTextureDim1D = u1- , maxTextureDim2D = (u21,u22)- , maxTextureDim3D = (u31,u32,u33)-#endif-#if CUDART_VERSION >= 3010- , eccEnabled = ee-#endif-#if CUDART_VERSION >= 3000 && CUDART_VERSION < 3010- -- not visible from CUDA runtime API 3.0- , eccEnabled = False-#endif-#if CUDART_VERSION >= 4000- , asyncEngineCount = ae- , cacheMemL2 = l2- , maxThreadsPerMultiProcessor = tm- , memBusWidth = mw- , memClockRate = mc- , tccDriverEnabled = tc- , unifiedAddressing = ua- , pciInfo = PCI pb pd pm-#endif-#if CUDA_VERSION >= 5050- , streamPriorities = sp-#endif-#if CUDA_VERSION >= 6000- , globalL1Cache = gl1- , localL1Cache = ll1- , managedMemory = mm- , multiGPUBoard = mg- , multiGPUBoardGroupID = mid-#endif- }-------------------------------------------------------------------------------------- Device Management------------------------------------------------------------------------------------- |--- Select the compute device which best matches the given criteria----{-# INLINEABLE choose #-}-choose :: DeviceProperties -> IO Device-choose !dev = resultIfOk =<< cudaChooseDevice dev--{-# INLINE cudaChooseDevice #-}-{# fun unsafe cudaChooseDevice- { alloca- `Int' peekIntConv*- , withDevProp* `DeviceProperties' } -> `Status' cToEnum #}- where- withDevProp = with----- |--- Returns which device is currently being used----{-# INLINEABLE get #-}-get :: IO Device-get = resultIfOk =<< cudaGetDevice--{-# INLINE cudaGetDevice #-}-{# fun unsafe cudaGetDevice- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}----- |--- Returns the number of devices available for execution, with compute--- capability >= 1.0----{-# INLINEABLE count #-}-count :: IO Int-count = resultIfOk =<< cudaGetDeviceCount--{-# INLINE cudaGetDeviceCount #-}-{# fun unsafe cudaGetDeviceCount- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}----- |--- Return information about the selected compute device----{-# INLINEABLE props #-}-props :: Device -> IO DeviceProperties-props !n = resultIfOk =<< cudaGetDeviceProperties n--{-# INLINE cudaGetDeviceProperties #-}-{# fun unsafe cudaGetDeviceProperties- { alloca- `DeviceProperties' peek*- , `Int' } -> `Status' cToEnum #}----- |--- Set device to be used for GPU execution----{-# INLINEABLE set #-}-set :: Device -> IO ()-set !n = nothingIfOk =<< cudaSetDevice n--{-# INLINE cudaSetDevice #-}-{# fun unsafe cudaSetDevice- { `Int' } -> `Status' cToEnum #}----- |--- Set flags to be used for device executions----{-# INLINEABLE setFlags #-}-setFlags :: [DeviceFlag] -> IO ()-setFlags !f = nothingIfOk =<< cudaSetDeviceFlags (combineBitMasks f)--{-# INLINE cudaSetDeviceFlags #-}-{# fun unsafe cudaSetDeviceFlags- { `Int' } -> `Status' cToEnum #}----- |--- Set list of devices for CUDA execution in priority order----{-# INLINEABLE setOrder #-}-setOrder :: [Device] -> IO ()-setOrder !l = nothingIfOk =<< cudaSetValidDevices l (length l)--{-# INLINE cudaSetValidDevices #-}-{# fun unsafe cudaSetValidDevices- { withArrayIntConv* `[Int]'- , `Int' } -> `Status' cToEnum #}- where- withArrayIntConv = withArray . map cIntConv---- |--- Block until the device has completed all preceding requested tasks. Returns--- an error if one of the tasks fails.----{-# INLINEABLE sync #-}-sync :: IO ()-#if CUDART_VERSION < 4000-{-# INLINE cudaThreadSynchronize #-}-sync = nothingIfOk =<< cudaThreadSynchronize-{# fun cudaThreadSynchronize { } -> `Status' cToEnum #}-#else-{-# INLINE cudaDeviceSynchronize #-}-sync = nothingIfOk =<< cudaDeviceSynchronize-{# fun cudaDeviceSynchronize { } -> `Status' cToEnum #}-#endif---- |--- Explicitly destroys and cleans up all runtime resources associated with the--- current device in the current process. Any subsequent API call will--- reinitialise the device.------ Note that this function will reset the device immediately. It is the caller’s--- responsibility to ensure that the device is not being accessed by any other--- host threads from the process when this function is called.----{-# INLINEABLE reset #-}-reset :: IO ()-#if CUDART_VERSION >= 4000-{-# INLINE cudaDeviceReset #-}-reset = nothingIfOk =<< cudaDeviceReset-{# fun unsafe cudaDeviceReset { } -> `Status' cToEnum #}-#else-{-# INLINE cudaThreadExit #-}-reset = nothingIfOk =<< cudaThreadExit-{# fun unsafe cudaThreadExit { } -> `Status' cToEnum #}-#endif-------------------------------------------------------------------------------------- Peer Access------------------------------------------------------------------------------------- |--- Possible option values for direct peer memory access----data PeerFlag-instance Enum PeerFlag where-#ifdef USE_EMPTY_CASE- toEnum x = case x of {}- fromEnum x = case x of {}-#endif---- |--- Queries if the first device can directly access the memory of the second. If--- direct access is possible, it can then be enabled with 'add'. Requires--- cuda-4.0.----{-# INLINEABLE accessible #-}-accessible :: Device -> Device -> IO Bool-#if CUDART_VERSION < 4000-accessible _ _ = requireSDK 'accessible 4.0-#else-accessible !dev !peer = resultIfOk =<< cudaDeviceCanAccessPeer dev peer--{-# INLINE cudaDeviceCanAccessPeer #-}-{# fun unsafe cudaDeviceCanAccessPeer- { alloca- `Bool' peekBool*- , cIntConv `Device'- , cIntConv `Device' } -> `Status' cToEnum #}-#endif---- |--- If the devices of both the current and supplied contexts support unified--- addressing, then enable allocations in the supplied context to be accessible--- by the current context. Requires cuda-4.0.----{-# INLINEABLE add #-}-add :: Device -> [PeerFlag] -> IO ()-#if CUDART_VERSION < 4000-add _ _ = requireSDK 'add 4.0-#else-add !dev !flags = nothingIfOk =<< cudaDeviceEnablePeerAccess dev flags--{-# INLINE cudaDeviceEnablePeerAccess #-}-{# fun unsafe cudaDeviceEnablePeerAccess- { cIntConv `Device'- , combineBitMasks `[PeerFlag]' } -> `Status' cToEnum #}-#endif----- |--- Disable direct memory access from the current context to the supplied--- context. Requires cuda-4.0.----{-# INLINEABLE remove #-}-remove :: Device -> IO ()-#if CUDART_VERSION < 4000-remove _ = requireSDK 'remove 4.0-#else-remove !dev = nothingIfOk =<< cudaDeviceDisablePeerAccess dev--{-# INLINE cudaDeviceDisablePeerAccess #-}-{# fun unsafe cudaDeviceDisablePeerAccess- { cIntConv `Device' } -> `Status' cToEnum #}-#endif-------------------------------------------------------------------------------------- Cache Configuration------------------------------------------------------------------------------------- |--- Device limit flags----#if CUDART_VERSION < 3010-data Limit-#else-{# enum cudaLimit as Limit- { underscoreToCase }- with prefix="cudaLimit" deriving (Eq, Show) #}-#endif----- |--- Query compute 2.0 call stack limits. Requires cuda-3.1.----{-# INLINEABLE getLimit #-}-getLimit :: Limit -> IO Int-#if CUDART_VERSION < 3010-getLimit _ = requireSDK 'getLimit 3.1-#elif CUDART_VERSION < 4000-getLimit !l = resultIfOk =<< cudaThreadGetLimit l--{-# INLINE cudaThreadGetLimit #-}-{# fun unsafe cudaThreadGetLimit- { alloca- `Int' peekIntConv*- , cFromEnum `Limit' } -> `Status' cToEnum #}-#else-getLimit !l = resultIfOk =<< cudaDeviceGetLimit l--{-# INLINE cudaDeviceGetLimit #-}-{# fun unsafe cudaDeviceGetLimit- { alloca- `Int' peekIntConv*- , cFromEnum `Limit' } -> `Status' cToEnum #}-#endif----- |--- Set compute 2.0 call stack limits. Requires cuda-3.1.----{-# INLINEABLE setLimit #-}-setLimit :: Limit -> Int -> IO ()-#if CUDART_VERSION < 3010-setLimit _ _ = requireSDK 'setLimit 3.1-#elif CUDART_VERSION < 4000-setLimit !l !n = nothingIfOk =<< cudaThreadSetLimit l n--{-# INLINE cudaThreadSetLimit #-}-{# fun unsafe cudaThreadSetLimit- { cFromEnum `Limit'- , cIntConv `Int' } -> `Status' cToEnum #}-#else-setLimit !l !n = nothingIfOk =<< cudaDeviceSetLimit l n--{-# INLINE cudaDeviceSetLimit #-}-{# fun unsafe cudaDeviceSetLimit- { cFromEnum `Limit'- , cIntConv `Int' } -> `Status' cToEnum #}-#endif-
− Foreign/CUDA/Runtime/Error.chs
@@ -1,116 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Error--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Error handling functions--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Error (-- Status(..), CUDAException(..),-- cudaError, describe, requireSDK,- resultIfOk, nothingIfOk--) where---- Friends-import Foreign.CUDA.Internal.C2HS---- System-import Control.Exception-import Data.Typeable-import Foreign.C-import Foreign.Ptr-import Language.Haskell.TH-import System.IO.Unsafe-import Text.Printf--#include "cbits/stubs.h"-{# context lib="cudart" #}-------------------------------------------------------------------------------------- Return Status------------------------------------------------------------------------------------- |--- Return codes from API functions----{# enum cudaError as Status- { cudaSuccess as Success }- with prefix="cudaError" deriving (Eq, Show) #}------------------------------------------------------------------------------------- Exceptions-----------------------------------------------------------------------------------data CUDAException- = ExitCode Status- | UserError String- deriving Typeable--instance Exception CUDAException--instance Show CUDAException where- showsPrec _ (ExitCode s) = showString ("CUDA Exception: " ++ describe s)- showsPrec _ (UserError s) = showString ("CUDA Exception: " ++ s)----- |--- Raise a 'CUDAException' in the IO Monad----cudaError :: String -> IO a-cudaError s = throwIO (UserError s)---- |--- A specially formatted error message----requireSDK :: Name -> Double -> IO a-requireSDK n v = cudaError $ printf "'%s' requires at least cuda-%3.1f\n" (show n) v-------------------------------------------------------------------------------------- Helper Functions------------------------------------------------------------------------------------- |--- Return the descriptive string associated with a particular error code----{# fun pure unsafe cudaGetErrorString as describe- { cFromEnum `Status' } -> `String' #}------ Logically, this must be a pure function, returning a pointer to a statically--- defined string constant.-------- |--- Return the results of a function on successful execution, otherwise return--- the error string associated with the return code----{-# INLINE resultIfOk #-}-resultIfOk :: (Status, a) -> IO a-resultIfOk (status, !result) =- case status of- Success -> return result- _ -> throwIO (ExitCode status)----- |--- Return the error string associated with an unsuccessful return code,--- otherwise Nothing----{-# INLINE nothingIfOk #-}-nothingIfOk :: Status -> IO ()-nothingIfOk status =- case status of- Success -> return ()- _ -> throwIO (ExitCode status)-
− Foreign/CUDA/Runtime/Event.chs
@@ -1,148 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Driver.Event--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Event management for C-for-CUDA runtime environment--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Event (-- -- * Event Management- Event, EventFlag(..), WaitFlag,- create, destroy, elapsedTime, query, record, wait, block--) where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Types-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad ( liftM )-import Control.Exception ( throwIO )-import Data.Maybe ( fromMaybe )-------------------------------------------------------------------------------------- Event management------------------------------------------------------------------------------------- |--- Create a new event----{-# INLINEABLE create #-}-create :: [EventFlag] -> IO Event-create !flags = resultIfOk =<< cudaEventCreateWithFlags flags--{-# INLINE cudaEventCreateWithFlags #-}-{# fun unsafe cudaEventCreateWithFlags- { alloca- `Event' peekEvt*- , combineBitMasks `[EventFlag]' } -> `Status' cToEnum #}- where peekEvt = liftM Event . peek----- |--- Destroy an event----{-# INLINEABLE destroy #-}-destroy :: Event -> IO ()-destroy !ev = nothingIfOk =<< cudaEventDestroy ev--{-# INLINE cudaEventDestroy #-}-{# fun unsafe cudaEventDestroy- { useEvent `Event' } -> `Status' cToEnum #}----- |--- Determine the elapsed time (in milliseconds) between two events----{-# INLINEABLE elapsedTime #-}-elapsedTime :: Event -> Event -> IO Float-elapsedTime !ev1 !ev2 = resultIfOk =<< cudaEventElapsedTime ev1 ev2--{-# INLINE cudaEventElapsedTime #-}-{# fun unsafe cudaEventElapsedTime- { alloca- `Float' peekFloatConv*- , useEvent `Event'- , useEvent `Event' } -> `Status' cToEnum #}----- |--- Determines if a event has actually been recorded----{-# INLINEABLE query #-}-query :: Event -> IO Bool-query !ev =- cudaEventQuery ev >>= \rv ->- case rv of- Success -> return True- NotReady -> return False- _ -> throwIO (ExitCode rv)--{-# INLINE cudaEventQuery #-}-{# fun unsafe cudaEventQuery- { useEvent `Event' } -> `Status' cToEnum #}----- |--- Record an event once all operations in the current context (or optionally--- specified stream) have completed. This operation is asynchronous.----{-# INLINEABLE record #-}-record :: Event -> Maybe Stream -> IO ()-record !ev !mst =- nothingIfOk =<< cudaEventRecord ev (maybe defaultStream id mst)--{-# INLINE cudaEventRecord #-}-{# fun unsafe cudaEventRecord- { useEvent `Event'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Makes all future work submitted to the (optional) stream wait until the given--- event reports completion before beginning execution. Synchronisation is--- performed on the device, including when the event and stream are from--- different device contexts. Requires cuda-3.2.----{-# INLINEABLE wait #-}-wait :: Event -> Maybe Stream -> [WaitFlag] -> IO ()-#if CUDART_VERSION < 3020-wait _ _ _ = requireSDK 'wait 3.2-#else-wait !ev !mst !flags =- let st = fromMaybe defaultStream mst- in nothingIfOk =<< cudaStreamWaitEvent st ev flags--{-# INLINE cudaStreamWaitEvent #-}-{# fun unsafe cudaStreamWaitEvent- { useStream `Stream'- , useEvent `Event'- , combineBitMasks `[WaitFlag]' } -> `Status' cToEnum #}-#endif---- |--- Wait until the event has been recorded----{-# INLINEABLE block #-}-block :: Event -> IO ()-block !ev = nothingIfOk =<< cudaEventSynchronize ev--{-# INLINE cudaEventSynchronize #-}-{# fun cudaEventSynchronize- { useEvent `Event' } -> `Status' cToEnum #}-
− Foreign/CUDA/Runtime/Exec.chs
@@ -1,276 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Exec--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Kernel execution control for C-for-CUDA runtime interface--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Exec (-- -- * Kernel Execution- Fun, FunAttributes(..), FunParam(..), CacheConfig(..),- attributes, setConfig, setParams, setCacheConfig, launch, launchKernel,--) where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Runtime.Stream ( Stream(..), defaultStream )-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad--#c-typedef struct cudaFuncAttributes cudaFuncAttributes;-#endc-------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |--- A @__global__@ device function.------ Note that the use of a string naming a function was deprecated in CUDA 4.1--- and removed in CUDA 5.0.----#if CUDART_VERSION >= 5000-type Fun = FunPtr ()-#else-type Fun = String-#endif-------- Function Attributes----{# pointer *cudaFuncAttributes as ^ foreign -> FunAttributes nocode #}--data FunAttributes = FunAttributes- {- constSizeBytes :: !Int64,- localSizeBytes :: !Int64,- sharedSizeBytes :: !Int64,- maxKernelThreadsPerBlock :: !Int, -- ^ maximum block size that can be successively launched (based on register usage)- numRegs :: !Int -- ^ number of registers required for each thread- }- deriving (Show)--instance Storable FunAttributes where- sizeOf _ = {# sizeof cudaFuncAttributes #}- alignment _ = alignment (undefined :: Ptr ())-- poke _ _ = error "Can not poke Foreign.CUDA.Runtime.FunAttributes"- peek p = do- cs <- cIntConv `fmap` {#get cudaFuncAttributes.constSizeBytes#} p- ls <- cIntConv `fmap` {#get cudaFuncAttributes.localSizeBytes#} p- ss <- cIntConv `fmap` {#get cudaFuncAttributes.sharedSizeBytes#} p- tb <- cIntConv `fmap` {#get cudaFuncAttributes.maxThreadsPerBlock#} p- nr <- cIntConv `fmap` {#get cudaFuncAttributes.numRegs#} p-- return FunAttributes- {- constSizeBytes = cs,- localSizeBytes = ls,- sharedSizeBytes = ss,- maxKernelThreadsPerBlock = tb,- numRegs = nr- }--#if CUDART_VERSION < 3000-data CacheConfig-#else--- |--- Cache configuration preference----{# enum cudaFuncCache as CacheConfig- { }- with prefix="cudaFuncCachePrefer" deriving (Eq, Show) #}-#endif---- |--- Kernel function parameters. Doubles will be converted to an internal float--- representation on devices that do not support doubles natively.----data FunParam where- IArg :: !Int -> FunParam- FArg :: !Float -> FunParam- DArg :: !Double -> FunParam- VArg :: Storable a => !a -> FunParam-------------------------------------------------------------------------------------- Execution Control------------------------------------------------------------------------------------- |--- Obtain the attributes of the named @__global__@ device function. This--- itemises the requirements to successfully launch the given kernel.----{-# INLINEABLE attributes #-}-attributes :: Fun -> IO FunAttributes-attributes !fn = resultIfOk =<< cudaFuncGetAttributes fn--{-# INLINE cudaFuncGetAttributes #-}-{# fun unsafe cudaFuncGetAttributes- { alloca- `FunAttributes' peek*- , withFun* `Fun' } -> `Status' cToEnum #}----- |--- Specify the grid and block dimensions for a device call. Used in conjunction--- with 'setParams', this pushes data onto the execution stack that will be--- popped when a function is 'launch'ed.----{-# INLINEABLE setConfig #-}-setConfig :: (Int,Int) -- ^ grid dimensions- -> (Int,Int,Int) -- ^ block dimensions- -> Int64 -- ^ shared memory per block (bytes)- -> Maybe Stream -- ^ associated processing stream- -> IO ()-setConfig (!gx,!gy) (!bx,!by,!bz) !sharedMem !mst =- nothingIfOk =<<- cudaConfigureCallSimple gx gy bx by bz sharedMem (maybe defaultStream id mst)-------- The FFI does not support passing deferenced structures to C functions, as--- this is highly platform/compiler dependent. Wrap our own function stub--- accepting plain integers.----{-# INLINE cudaConfigureCallSimple #-}-{# fun unsafe cudaConfigureCallSimple- { `Int', `Int'- , `Int', `Int', `Int'- , cIntConv `Int64'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Set the argument parameters that will be passed to the next kernel--- invocation. This is used in conjunction with 'setConfig' to control kernel--- execution.----{-# INLINEABLE setParams #-}-setParams :: [FunParam] -> IO ()-setParams = foldM_ k 0- where- k !offset !arg = do- let s = size arg- set arg s offset >>= nothingIfOk- return (offset + s)-- size (IArg _) = sizeOf (undefined :: Int)- size (FArg _) = sizeOf (undefined :: Float)- size (DArg _) = sizeOf (undefined :: Double)- size (VArg a) = sizeOf a-- set (IArg v) s o = cudaSetupArgument v s o- set (FArg v) s o = cudaSetupArgument v s o- set (VArg v) s o = cudaSetupArgument v s o- set (DArg v) s o =- cudaSetDoubleForDevice v >>= resultIfOk >>= \d ->- cudaSetupArgument d s o---{-# INLINE cudaSetupArgument #-}-{# fun unsafe cudaSetupArgument- `Storable a' =>- { with'* `a'- , `Int'- , `Int' } -> `Status' cToEnum #}- where- with' v a = with v $ \p -> a (castPtr p)--{-# INLINE cudaSetDoubleForDevice #-}-{# fun unsafe cudaSetDoubleForDevice- { with'* `Double' peek'* } -> `Status' cToEnum #}- where- with' v a = with v $ \p -> a (castPtr p)- peek' = peek . castPtr----- |--- On devices where the L1 cache and shared memory use the same hardware--- resources, this sets the preferred cache configuration for the given device--- function. This is only a preference; the driver is free to choose a different--- configuration as required to execute the function.------ Switching between configuration modes may insert a device-side--- synchronisation point for streamed kernel launches----{-# INLINEABLE setCacheConfig #-}-setCacheConfig :: Fun -> CacheConfig -> IO ()-#if CUDART_VERSION < 3000-setCacheConfig _ _ = requireSDK 'setCacheConfig 3.0-#else-setCacheConfig !fn !pref = nothingIfOk =<< cudaFuncSetCacheConfig fn pref--{-# INLINE cudaFuncSetCacheConfig #-}-{# fun unsafe cudaFuncSetCacheConfig- { withFun* `Fun'- , cFromEnum `CacheConfig' } -> `Status' cToEnum #}-#endif----- |--- Invoke the @__global__@ kernel function on the device. This must be preceded--- by a call to 'setConfig' and (if appropriate) 'setParams'.----{-# INLINEABLE launch #-}-launch :: Fun -> IO ()-launch !fn = nothingIfOk =<< cudaLaunch fn--{-# INLINE cudaLaunch #-}-{# fun unsafe cudaLaunch- { withFun* `Fun' } -> `Status' cToEnum #}----- |--- Invoke a kernel on a @(gx * gy)@ grid of blocks, where each block contains--- @(tx * ty * tz)@ threads and has access to a given number of bytes of shared--- memory. The launch may also be associated with a specific 'Stream'.----{-# INLINEABLE launchKernel #-}-launchKernel- :: Fun -- ^ Device function symbol- -> (Int,Int) -- ^ grid dimensions- -> (Int,Int,Int) -- ^ thread block shape- -> Int64 -- ^ shared memory per block (bytes)- -> Maybe Stream -- ^ (optional) execution stream- -> [FunParam]- -> IO ()-launchKernel !fn !grid !block !sm !mst !args = do- setConfig grid block sm mst- setParams args- launch fn------------------------------------------------------------------------------------- Internals------------------------------------------------------------------------------------- CUDA 5.0 changed the type of a kernel function from char* to void*----#if CUDART_VERSION >= 5000-withFun :: Fun -> (Ptr a -> IO b) -> IO b-withFun fn action = action (castFunPtrToPtr fn)-#else-withFun :: Fun -> (Ptr CChar -> IO a) -> IO a-withFun = withCString-#endif-
− Foreign/CUDA/Runtime/Marshal.chs
@@ -1,648 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE ForeignFunctionInterface #-}-{-# LANGUAGE TemplateHaskell #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Marshal--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Memory management for CUDA devices--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Marshal (-- -- * Host Allocation- AllocFlag(..),- mallocHostArray, freeHost,-- -- * Device Allocation- mallocArray, allocaArray, free,-- -- * Unified Memory Allocation- AttachFlag(..),- mallocManagedArray,-- -- * Marshalling- peekArray, peekArrayAsync, peekArray2D, peekArray2DAsync, peekListArray,- pokeArray, pokeArrayAsync, pokeArray2D, pokeArray2DAsync, pokeListArray,- copyArray, copyArrayAsync, copyArray2D, copyArray2DAsync,-- -- * Combined Allocation and Marshalling- newListArray, newListArrayLen,- withListArray, withListArrayLen,-- -- * Utility- memset--) where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Ptr-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Runtime.Stream-import Foreign.CUDA.Internal.C2HS---- System-import Data.Int-import Data.Maybe-import Control.Exception--import Foreign.C-import Foreign.Ptr-import Foreign.Storable-import qualified Foreign.Marshal as F--#c-typedef enum cudaMemHostAlloc_option_enum {-// CUDA_MEMHOSTALLOC_OPTION_DEFAULT = cudaHostAllocDefault,- CUDA_MEMHOSTALLOC_OPTION_DEVICE_MAPPED = cudaHostAllocMapped,- CUDA_MEMHOSTALLOC_OPTION_PORTABLE = cudaHostAllocPortable,- CUDA_MEMHOSTALLOC_OPTION_WRITE_COMBINED = cudaHostAllocWriteCombined-} cudaMemHostAlloc_option;-#endc--#if CUDART_VERSION >= 6000-#c-typedef enum cudaMemAttachFlags_option_enum {- CUDA_MEM_ATTACH_OPTION_GLOBAL = cudaMemAttachGlobal,- CUDA_MEM_ATTACH_OPTION_HOST = cudaMemAttachHost,- CUDA_MEM_ATTACH_OPTION_SINGLE = cudaMemAttachSingle-} cudaMemAttachFlags_option;-#endc-#endif-------------------------------------------------------------------------------------- Host Allocation------------------------------------------------------------------------------------- |--- Options for host allocation----{# enum cudaMemHostAlloc_option as AllocFlag- { underscoreToCase }- with prefix="CUDA_MEMHOSTALLOC_OPTION" deriving (Eq, Show, Bounded) #}----- |--- Allocate a section of linear memory on the host which is page-locked and--- directly accessible from the device. The storage is sufficient to hold the--- given number of elements of a storable type. The runtime system automatically--- accelerates calls to functions such as 'peekArrayAsync' and 'pokeArrayAsync'--- that refer to page-locked memory.------ Note that since the amount of pageable memory is thusly reduced, overall--- system performance may suffer. This is best used sparingly to allocate--- staging areas for data exchange----{-# INLINEABLE mallocHostArray #-}-mallocHostArray :: Storable a => [AllocFlag] -> Int -> IO (HostPtr a)-mallocHostArray !flags = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (HostPtr a')- doMalloc x !n = resultIfOk =<< cudaHostAlloc (fromIntegral n * fromIntegral (sizeOf x)) flags--{-# INLINE cudaHostAlloc #-}-{# fun unsafe cudaHostAlloc- { alloca'- `HostPtr a' hptr*- , cIntConv `Int64'- , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}- where- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)- hptr !p = (HostPtr . castPtr) `fmap` peek p----- |--- Free page-locked host memory previously allocated with 'mallecHost'----{-# INLINEABLE freeHost #-}-freeHost :: HostPtr a -> IO ()-freeHost !p = nothingIfOk =<< cudaFreeHost p--{-# INLINE cudaFreeHost #-}-{# fun unsafe cudaFreeHost- { hptr `HostPtr a' } -> `Status' cToEnum #}- where hptr = castPtr . useHostPtr-------------------------------------------------------------------------------------- Device Allocation------------------------------------------------------------------------------------- |--- Allocate a section of linear memory on the device, and return a reference to--- it. The memory is sufficient to hold the given number of elements of storable--- type. It is suitable aligned, and not cleared.----{-# INLINEABLE mallocArray #-}-mallocArray :: Storable a => Int -> IO (DevicePtr a)-mallocArray = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')- doMalloc x !n = resultIfOk =<< cudaMalloc (fromIntegral n * fromIntegral (sizeOf x))--{-# INLINE cudaMalloc #-}-{# fun unsafe cudaMalloc- { alloca'- `DevicePtr a' dptr*- , cIntConv `Int64' } -> `Status' cToEnum #}- where- -- C-> Haskell doesn't like qualified imports in marshaller specifications- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)- dptr !p = (castDevPtr . DevicePtr) `fmap` peek p----- |--- Execute a computation, passing a pointer to a temporarily allocated block of--- memory sufficient to hold the given number of elements of storable type. The--- memory is freed when the computation terminates (normally or via an--- exception), so the pointer must not be used after this.------ Note that kernel launches can be asynchronous, so you may need to add a--- synchronisation point at the end of the computation.----{-# INLINEABLE allocaArray #-}-allocaArray :: Storable a => Int -> (DevicePtr a -> IO b) -> IO b-allocaArray n = bracket (mallocArray n) free----- |--- Free previously allocated memory on the device----{-# INLINEABLE free #-}-free :: DevicePtr a -> IO ()-free !p = nothingIfOk =<< cudaFree p--{-# INLINE cudaFree #-}-{# fun unsafe cudaFree- { dptr `DevicePtr a' } -> `Status' cToEnum #}- where- dptr = useDevicePtr . castDevPtr-------------------------------------------------------------------------------------- Unified memory allocation------------------------------------------------------------------------------------- |--- Options for unified memory allocations----#if CUDART_VERSION >= 6000-{# enum cudaMemAttachFlags_option as AttachFlag- { underscoreToCase }- with prefix="CUDA_MEM_ATTACH_OPTION" deriving (Eq, Show, Bounded) #}-#else-data AttachFlag-#endif---- |--- Allocates memory that will be automatically managed by the Unified Memory--- system----{-# INLINEABLE mallocManagedArray #-}-mallocManagedArray :: Storable a => [AttachFlag] -> Int -> IO (DevicePtr a)-#if CUDART_VERSION < 6000-mallocManagedArray _ _ = requireSDK 'mallocManagedArray 6.0-#else-mallocManagedArray !flags = doMalloc undefined- where- doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')- doMalloc x !n = resultIfOk =<< cudaMallocManaged (fromIntegral n * fromIntegral (sizeOf x)) flags--{-# INLINE cudaMallocManaged #-}-{# fun unsafe cudaMallocManaged- { alloca'- `DevicePtr a' dptr*- , cIntConv `Int64'- , combineBitMasks `[AttachFlag]' } -> `Status' cToEnum #}- where- alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)- dptr !p = (castDevPtr . DevicePtr) `fmap` peek p-#endif-------------------------------------------------------------------------------------- Marshalling------------------------------------------------------------------------------------- |--- Copy a number of elements from the device to host memory. This is a--- synchronous operation.----{-# INLINEABLE peekArray #-}-peekArray :: Storable a => Int -> DevicePtr a -> Ptr a -> IO ()-peekArray !n !dptr !hptr = memcpy hptr (useDevicePtr dptr) n DeviceToHost----- |--- Copy memory from the device asynchronously, possibly associated with a--- particular stream. The destination memory must be page locked.----{-# INLINEABLE peekArrayAsync #-}-peekArrayAsync :: Storable a => Int -> DevicePtr a -> HostPtr a -> Maybe Stream -> IO ()-peekArrayAsync !n !dptr !hptr !mst =- memcpyAsync (useHostPtr hptr) (useDevicePtr dptr) n DeviceToHost mst----- |--- Copy a 2D memory area from the device to the host. This is a synchronous--- operation.----{-# INLINEABLE peekArray2D #-}-peekArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> Ptr a -- ^ destination array- -> Int -- ^ destination array width- -> IO ()-peekArray2D !w !h !dptr !dw !hptr !hw =- memcpy2D hptr hw (useDevicePtr dptr) dw w h DeviceToHost----- |--- Copy a 2D memory area from the device to the host asynchronously, possibly--- associated with a particular stream. The destination array must be page--- locked.----{-# INLINEABLE peekArray2DAsync #-}-peekArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> HostPtr a -- ^ destination array- -> Int -- ^ destination array width- -> Maybe Stream- -> IO ()-peekArray2DAsync !w !h !dptr !dw !hptr !hw !mst =- memcpy2DAsync (useHostPtr hptr) hw (useDevicePtr dptr) dw w h DeviceToHost mst----- |--- Copy a number of elements from the device into a new Haskell list. Note that--- this requires two memory copies: firstly from the device into a heap--- allocated array, and from there marshalled into a list----{-# INLINEABLE peekListArray #-}-peekListArray :: Storable a => Int -> DevicePtr a -> IO [a]-peekListArray !n !dptr =- F.allocaArray n $ \p -> do- peekArray n dptr p- F.peekArray n p----- |--- Copy a number of elements onto the device. This is a synchronous operation.----{-# INLINEABLE pokeArray #-}-pokeArray :: Storable a => Int -> Ptr a -> DevicePtr a -> IO ()-pokeArray !n !hptr !dptr = memcpy (useDevicePtr dptr) hptr n HostToDevice----- |--- Copy memory onto the device asynchronously, possibly associated with a--- particular stream. The source memory must be page-locked.----{-# INLINEABLE pokeArrayAsync #-}-pokeArrayAsync :: Storable a => Int -> HostPtr a -> DevicePtr a -> Maybe Stream -> IO ()-pokeArrayAsync !n !hptr !dptr !mst =- memcpyAsync (useDevicePtr dptr) (useHostPtr hptr) n HostToDevice mst----- |--- Copy a 2D memory area onto the device. This is a synchronous operation.----{-# INLINEABLE pokeArray2D #-}-pokeArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> Ptr a -- ^ source array- -> Int -- ^ source array width- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> IO ()-pokeArray2D !w !h !hptr !dw !dptr !hw =- memcpy2D (useDevicePtr dptr) dw hptr hw w h HostToDevice----- |--- Copy a 2D memory area onto the device asynchronously, possibly associated--- with a particular stream. The source array must be page locked.----{-# INLINEABLE pokeArray2DAsync #-}-pokeArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> HostPtr a -- ^ source array- -> Int -- ^ source array width- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Maybe Stream- -> IO ()-pokeArray2DAsync !w !h !hptr !hw !dptr !dw !mst =- memcpy2DAsync (useDevicePtr dptr) dw (useHostPtr hptr) hw w h HostToDevice mst---- |--- Write a list of storable elements into a device array. The array must be--- sufficiently large to hold the entire list. This requires two marshalling--- operations----{-# INLINEABLE pokeListArray #-}-pokeListArray :: Storable a => [a] -> DevicePtr a -> IO ()-pokeListArray !xs !dptr = F.withArrayLen xs $ \len p -> pokeArray len p dptr----- |--- Copy the given number of elements from the first device array (source) to the--- second (destination). The copied areas may not overlap. This operation is--- asynchronous with respect to host, but will not overlap other device--- operations.----{-# INLINEABLE copyArray #-}-copyArray :: Storable a => Int -> DevicePtr a -> DevicePtr a -> IO ()-copyArray !n !src !dst = memcpy (useDevicePtr dst) (useDevicePtr src) n DeviceToDevice----- |--- Copy the given number of elements from the first device array (source) to the--- second (destination). The copied areas may not overlap. This operation is--- asynchronous with respect to the host, and may be associated with a--- particular stream.----{-# INLINEABLE copyArrayAsync #-}-copyArrayAsync :: Storable a => Int -> DevicePtr a -> DevicePtr a -> Maybe Stream -> IO ()-copyArrayAsync !n !src !dst !mst =- memcpyAsync (useDevicePtr dst) (useDevicePtr src) n DeviceToDevice mst----- |--- Copy a 2D memory area from the first device array (source) to the second--- (destination). The copied areas may not overlap. This operation is--- asynchronous with respect to the host, but will not overlap other device--- operations.----{-# INLINEABLE copyArray2D #-}-copyArray2D- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> IO ()-copyArray2D !w !h !src !sw !dst !dw =- memcpy2D (useDevicePtr dst) dw (useDevicePtr src) sw w h DeviceToDevice----- |--- Copy a 2D memory area from the first device array (source) to the second--- device array (destination). The copied areas may not overlay. This operation--- is asynchronous with respect to the host, and may be associated with a--- particular stream.----{-# INLINEABLE copyArray2DAsync #-}-copyArray2DAsync- :: Storable a- => Int -- ^ width to copy (elements)- -> Int -- ^ height to copy (elements)- -> DevicePtr a -- ^ source array- -> Int -- ^ source array width- -> DevicePtr a -- ^ destination array- -> Int -- ^ destination array width- -> Maybe Stream- -> IO ()-copyArray2DAsync !w !h !src !sw !dst !dw !mst =- memcpy2DAsync (useDevicePtr dst) dw (useDevicePtr src) sw w h DeviceToDevice mst-------- Memory copy kind----{# enum cudaMemcpyKind as CopyDirection {}- with prefix="cudaMemcpy" deriving (Eq, Show) #}---- |--- Copy data between host and device. This is a synchronous operation.----{-# INLINEABLE memcpy #-}-memcpy :: Storable a- => Ptr a -- ^ destination- -> Ptr a -- ^ source- -> Int -- ^ number of elements- -> CopyDirection- -> IO ()-memcpy !dst !src !n !dir = doMemcpy undefined dst- where- doMemcpy :: Storable a' => a' -> Ptr a' -> IO ()- doMemcpy x _ =- nothingIfOk =<< cudaMemcpy dst src (fromIntegral n * fromIntegral (sizeOf x)) dir--{-# INLINE cudaMemcpy #-}-{# fun cudaMemcpy- { castPtr `Ptr a'- , castPtr `Ptr a'- , cIntConv `Int64'- , cFromEnum `CopyDirection' } -> `Status' cToEnum #}----- |--- Copy data between the host and device asynchronously, possibly associated--- with a particular stream. The host-side memory must be page-locked (allocated--- with 'mallocHostArray').----{-# INLINEABLE memcpyAsync #-}-memcpyAsync :: Storable a- => Ptr a -- ^ destination- -> Ptr a -- ^ source- -> Int -- ^ number of elements- -> CopyDirection- -> Maybe Stream- -> IO ()-memcpyAsync !dst !src !n !kind !mst = doMemcpy undefined dst- where- doMemcpy :: Storable a' => a' -> Ptr a' -> IO ()- doMemcpy x _ =- let bytes = fromIntegral n * fromIntegral (sizeOf x) in- nothingIfOk =<< cudaMemcpyAsync dst src bytes kind (fromMaybe defaultStream mst)--{-# INLINE cudaMemcpyAsync #-}-{# fun cudaMemcpyAsync- { castPtr `Ptr a'- , castPtr `Ptr a'- , cIntConv `Int64'- , cFromEnum `CopyDirection'- , useStream `Stream' } -> `Status' cToEnum #}----- |--- Copy a 2D memory area between the host and device. This is a synchronous--- operation.----{-# INLINEABLE memcpy2D #-}-memcpy2D :: Storable a- => Ptr a -- ^ destination- -> Int -- ^ width of destination array- -> Ptr a -- ^ source- -> Int -- ^ width of source array- -> Int -- ^ width to copy- -> Int -- ^ height to copy- -> CopyDirection- -> IO ()-memcpy2D !dst !dw !src !sw !w !h !kind = doCopy undefined dst- where- doCopy :: Storable a' => a' -> Ptr a' -> IO ()- doCopy x _ =- let bytes = fromIntegral (sizeOf x)- dw' = fromIntegral dw * bytes- sw' = fromIntegral sw * bytes- w' = fromIntegral w * bytes- h' = fromIntegral h- in- nothingIfOk =<< cudaMemcpy2D dst dw' src sw' w' h' kind--{-# INLINE cudaMemcpy2D #-}-{# fun cudaMemcpy2D- { castPtr `Ptr a'- , `Int64'- , castPtr `Ptr a'- , `Int64'- , `Int64'- , `Int64'- , cFromEnum `CopyDirection'- }- -> `Status' cToEnum #}----- |--- Copy a 2D memory area between the host and device asynchronously, possibly--- associated with a particular stream. The host-side memory must be--- page-locked.----{-# INLINEABLE memcpy2DAsync #-}-memcpy2DAsync :: Storable a- => Ptr a -- ^ destination- -> Int -- ^ width of destination array- -> Ptr a -- ^ source- -> Int -- ^ width of source array- -> Int -- ^ width to copy- -> Int -- ^ height to copy- -> CopyDirection- -> Maybe Stream- -> IO ()-memcpy2DAsync !dst !dw !src !sw !w !h !kind !mst = doCopy undefined dst- where- doCopy :: Storable a' => a' -> Ptr a' -> IO ()- doCopy x _ =- let bytes = fromIntegral (sizeOf x)- dw' = fromIntegral dw * bytes- sw' = fromIntegral sw * bytes- w' = fromIntegral w * bytes- h' = fromIntegral h- st = fromMaybe defaultStream mst- in- nothingIfOk =<< cudaMemcpy2DAsync dst dw' src sw' w' h' kind st--{-# INLINE cudaMemcpy2DAsync #-}-{# fun cudaMemcpy2DAsync- { castPtr `Ptr a'- , `Int64'- , castPtr `Ptr a'- , `Int64'- , `Int64'- , `Int64'- , cFromEnum `CopyDirection'- , useStream `Stream'- }- -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Combined Allocation and Marshalling------------------------------------------------------------------------------------- |--- Write a list of storable elements into a newly allocated device array,--- returning the device pointer together with the number of elements that were--- written. Note that this requires two copy operations: firstly from a Haskell--- list into a heap-allocated array, and from there into device memory. The--- array should be 'free'd when no longer required.----{-# INLINEABLE newListArrayLen #-}-newListArrayLen :: Storable a => [a] -> IO (DevicePtr a, Int)-newListArrayLen !xs =- F.withArrayLen xs $ \len p ->- bracketOnError (mallocArray len) free $ \d_xs -> do- pokeArray len p d_xs- return (d_xs, len)----- |--- Write a list of storable elements into a newly allocated device array. This--- is 'newListArrayLen' composed with 'fst'.----{-# INLINEABLE newListArray #-}-newListArray :: Storable a => [a] -> IO (DevicePtr a)-newListArray !xs = fst `fmap` newListArrayLen xs----- |--- Temporarily store a list of elements into a newly allocated device array. An--- IO action is applied to the array, the result of which is returned. Similar--- to 'newListArray', this requires two marshalling operations of the data.------ As with 'allocaArray', the memory is freed once the action completes, so you--- should not return the pointer from the action, and be sure that any--- asynchronous operations (such as kernel execution) have completed.----{-# INLINEABLE withListArray #-}-withListArray :: Storable a => [a] -> (DevicePtr a -> IO b) -> IO b-withListArray !xs = withListArrayLen xs . const----- |--- A variant of 'withListArray' which also supplies the number of elements in--- the array to the applied function----{-# INLINEABLE withListArrayLen #-}-withListArrayLen :: Storable a => [a] -> (Int -> DevicePtr a -> IO b) -> IO b-withListArrayLen !xs !f =- bracket (newListArrayLen xs) (free . fst) (uncurry . flip $ f)------ XXX: Will this attempt to double-free the device array on error (together--- with newListArrayLen)?----------------------------------------------------------------------------------------- Utility------------------------------------------------------------------------------------- |--- Initialise device memory to a given 8-bit value----{-# INLINEABLE memset #-}-memset :: DevicePtr a -- ^ The device memory- -> Int64 -- ^ Number of bytes- -> Int8 -- ^ Value to set for each byte- -> IO ()-memset !dptr !bytes !symbol = nothingIfOk =<< cudaMemset dptr symbol bytes--{-# INLINE cudaMemset #-}-{# fun unsafe cudaMemset- { dptr `DevicePtr a'- , cIntConv `Int8'- , cIntConv `Int64' } -> `Status' cToEnum #}- where- dptr = useDevicePtr . castDevPtr-
− Foreign/CUDA/Runtime/Stream.chs
@@ -1,115 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Stream--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Stream management routines--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Stream (-- -- * Stream Management- Stream(..),- create, destroy, finished, block, defaultStream--) where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Types-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C-import Control.Monad ( liftM )-import Control.Exception ( throwIO )-------------------------------------------------------------------------------------- Functions------------------------------------------------------------------------------------- |--- Create a new asynchronous stream----{-# INLINEABLE create #-}-create :: IO Stream-create = resultIfOk =<< cudaStreamCreate--{-# INLINE cudaStreamCreate #-}-{# fun unsafe cudaStreamCreate- { alloca- `Stream' peekStream* } -> `Status' cToEnum #}----- |--- Destroy and clean up an asynchronous stream----{-# INLINEABLE destroy #-}-destroy :: Stream -> IO ()-destroy !s = nothingIfOk =<< cudaStreamDestroy s--{-# INLINE cudaStreamDestroy #-}-{# fun unsafe cudaStreamDestroy- { useStream `Stream' } -> `Status' cToEnum #}----- |--- Determine if all operations in a stream have completed----{-# INLINEABLE finished #-}-finished :: Stream -> IO Bool-finished !s =- cudaStreamQuery s >>= \rv -> do- case rv of- Success -> return True- NotReady -> return False- _ -> throwIO (ExitCode rv)--{-# INLINE cudaStreamQuery #-}-{# fun unsafe cudaStreamQuery- { useStream `Stream' } -> `Status' cToEnum #}----- |--- Block until all operations in a Stream have been completed----{-# INLINEABLE block #-}-block :: Stream -> IO ()-block !s = nothingIfOk =<< cudaStreamSynchronize s--{-# INLINE cudaStreamSynchronize #-}-{# fun cudaStreamSynchronize- { useStream `Stream' } -> `Status' cToEnum #}----- |--- The main execution stream (0)------ {-# INLINE defaultStream #-}--- defaultStream :: Stream--- #if CUDART_VERSION < 3010--- defaultStream = Stream 0--- #else--- defaultStream = Stream nullPtr--- #endif------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------{-# INLINE peekStream #-}-peekStream :: Ptr {#type cudaStream_t#} -> IO Stream-#if CUDART_VERSION < 3010-peekStream = liftM Stream . peekIntConv-#else-peekStream = liftM Stream . peek-#endif-
− Foreign/CUDA/Runtime/Texture.chs
@@ -1,203 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Texture--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Texture references--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Texture (-- -- * Texture Reference Management- Texture(..), FormatKind(..), AddressMode(..), FilterMode(..), FormatDesc(..),- bind, bind2D--) where---- Friends-import Foreign.CUDA.Ptr-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Data.Int-import Foreign-import Foreign.C--#include "cbits/stubs.h"-{# context lib="cudart" #}--#c-typedef struct textureReference textureReference;-typedef struct cudaChannelFormatDesc cudaChannelFormatDesc;-#endc------------------------------------------------------------------------------------- Data Types------------------------------------------------------------------------------------- |A texture reference----{# pointer *textureReference as ^ -> Texture #}--data Texture = Texture- {- normalised :: !Bool, -- ^ access texture using normalised coordinates [0.0,1.0)- filtering :: !FilterMode,- addressing :: !(AddressMode, AddressMode, AddressMode),- format :: !FormatDesc- }- deriving (Eq, Show)---- |Texture channel format kind----{# enum cudaChannelFormatKind as FormatKind- { }- with prefix="cudaChannelFormatKind" deriving (Eq, Show) #}---- |Texture addressing mode----{# enum cudaTextureAddressMode as AddressMode- { }- with prefix="cudaAddressMode" deriving (Eq, Show) #}---- |Texture filtering mode----{# enum cudaTextureFilterMode as FilterMode- { }- with prefix="cudaFilterMode" deriving (Eq, Show) #}----- |A description of how memory read through the texture cache should be--- interpreted, including the kind of data and the number of bits of each--- component (x,y,z and w, respectively).----{# pointer *cudaChannelFormatDesc as ^ foreign -> FormatDesc nocode #}--data FormatDesc = FormatDesc- {- depth :: !(Int,Int,Int,Int),- kind :: !FormatKind- }- deriving (Eq, Show)--instance Storable FormatDesc where- sizeOf _ = {# sizeof cudaChannelFormatDesc #}- alignment _ = alignment (undefined :: Ptr ())-- peek p = do- dx <- cIntConv `fmap` {# get cudaChannelFormatDesc.x #} p- dy <- cIntConv `fmap` {# get cudaChannelFormatDesc.y #} p- dz <- cIntConv `fmap` {# get cudaChannelFormatDesc.z #} p- dw <- cIntConv `fmap` {# get cudaChannelFormatDesc.w #} p- df <- cToEnum `fmap` {# get cudaChannelFormatDesc.f #} p- return $ FormatDesc (dx,dy,dz,dw) df-- poke p (FormatDesc (x,y,z,w) k) = do- {# set cudaChannelFormatDesc.x #} p (cIntConv x)- {# set cudaChannelFormatDesc.y #} p (cIntConv y)- {# set cudaChannelFormatDesc.z #} p (cIntConv z)- {# set cudaChannelFormatDesc.w #} p (cIntConv w)- {# set cudaChannelFormatDesc.f #} p (cFromEnum k)---instance Storable Texture where- sizeOf _ = {# sizeof textureReference #}- alignment _ = alignment (undefined :: Ptr ())-- peek p = do- norm <- cToBool `fmap` {# get textureReference.normalized #} p- fmt <- cToEnum `fmap` {# get textureReference.filterMode #} p- dsc <- peek . castPtr =<< {# get textureReference.channelDesc #} p- [x,y,z] <- peekArrayWith cToEnum 3 =<< {# get textureReference.addressMode #} p- return $ Texture norm fmt (x,y,z) dsc-- poke p (Texture norm fmt (x,y,z) dsc) = do- {# set textureReference.normalized #} p (cFromBool norm)- {# set textureReference.filterMode #} p (cFromEnum fmt)- withArray (map cFromEnum [x,y,z]) ({# set textureReference.addressMode #} p)-- -- c2hs is returning the wrong type for structs-within-structs- dscptr <- {# get textureReference.channelDesc #} p- poke (castPtr dscptr) dsc-------------------------------------------------------------------------------------- Texture References------------------------------------------------------------------------------------- |Bind the memory area associated with the device pointer to a texture--- reference given by the named symbol. Any previously bound references are--- unbound.----{-# INLINEABLE bind #-}-bind :: String -> Texture -> DevicePtr a -> Int64 -> IO ()-bind !name !tex !dptr !bytes = do- ref <- getTex name- poke ref tex- nothingIfOk =<< cudaBindTexture ref dptr (format tex) bytes--{-# INLINE cudaBindTexture #-}-{# fun unsafe cudaBindTexture- { alloca- `Int'- , id `TextureReference'- , dptr `DevicePtr a'- , with_* `FormatDesc'- , `Int64' } -> `Status' cToEnum #}- where dptr = useDevicePtr . castDevPtr---- |Bind the two-dimensional memory area to the texture reference associated--- with the given symbol. The size of the area is constrained by (width,height)--- in texel units, and the row pitch in bytes. Any previously bound references--- are unbound.----{-# INLINEABLE bind2D #-}-bind2D :: String -> Texture -> DevicePtr a -> (Int,Int) -> Int64 -> IO ()-bind2D !name !tex !dptr (!width,!height) !bytes = do- ref <- getTex name- poke ref tex- nothingIfOk =<< cudaBindTexture2D ref dptr (format tex) width height bytes--{-# INLINE cudaBindTexture2D #-}-{# fun unsafe cudaBindTexture2D- { alloca- `Int'- , id `TextureReference'- , dptr `DevicePtr a'- , with_* `FormatDesc'- , `Int'- , `Int'- , `Int64' } -> `Status' cToEnum #}- where dptr = useDevicePtr . castDevPtr----- |Returns the texture reference associated with the given symbol----{-# INLINEABLE getTex #-}-getTex :: String -> IO TextureReference-getTex !name = resultIfOk =<< cudaGetTextureReference name--{-# INLINE cudaGetTextureReference #-}-{# fun unsafe cudaGetTextureReference- { alloca- `Ptr Texture' peek*- , withCString_* `String' } -> `Status' cToEnum #}-------------------------------------------------------------------------------------- Internal-----------------------------------------------------------------------------------{-# INLINE with_ #-}-with_ :: Storable a => a -> (Ptr a -> IO b) -> IO b-with_ = with----- CUDA 5.0 changed the types of some attributes from char* to void*----{-# INLINE withCString_ #-}-withCString_ :: String -> (Ptr a -> IO b) -> IO b-withCString_ !str !fn = withCString str (fn . castPtr)-
− Foreign/CUDA/Runtime/Utils.chs
@@ -1,49 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Runtime.Utils--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Utility functions--------------------------------------------------------------------------------------module Foreign.CUDA.Runtime.Utils (runtimeVersion, driverVersion)- where--#include "cbits/stubs.h"-{# context lib="cudart" #}---- Friends-import Foreign.CUDA.Runtime.Error-import Foreign.CUDA.Internal.C2HS---- System-import Foreign-import Foreign.C----- |--- Return the version number of the installed CUDA driver----{-# INLINEABLE runtimeVersion #-}-runtimeVersion :: IO Int-runtimeVersion = resultIfOk =<< cudaRuntimeGetVersion--{-# INLINE cudaRuntimeGetVersion #-}-{# fun unsafe cudaRuntimeGetVersion- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}----- |--- Return the version number of the installed CUDA runtime----{-# INLINEABLE driverVersion #-}-driverVersion :: IO Int-driverVersion = resultIfOk =<< cudaDriverGetVersion--{-# INLINE cudaDriverGetVersion #-}-{# fun unsafe cudaDriverGetVersion- { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}-
− Foreign/CUDA/Types.chs
@@ -1,155 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE EmptyDataDecls #-}-#ifdef USE_EMPTY_CASE-{-# LANGUAGE EmptyCase #-}-#endif------------------------------------------------------------------------------------ |--- Module : Foreign.CUDA.Types--- Copyright : [2009..2014] Trevor L. McDonell--- License : BSD------ Data types that are equivalent and can be shared freely between the CUDA--- Runtime and Driver APIs.--------------------------------------------------------------------------------------module Foreign.CUDA.Types (-- -- * Pointers- DevicePtr(..), HostPtr(..),-- -- * Events- Event(..), EventFlag(..), WaitFlag,-- -- * Streams- Stream(..), StreamPriority, StreamFlag,- defaultStream,--) where---- system-import Foreign.Ptr-import Foreign.Storable--#include "cbits/stubs.h"-{# context lib="cuda" #}-------------------------------------------------------------------------------------- Data pointers------------------------------------------------------------------------------------- |--- A reference to data stored on the device.----newtype DevicePtr a = DevicePtr { useDevicePtr :: Ptr a }- deriving (Eq,Ord)--instance Show (DevicePtr a) where- showsPrec n (DevicePtr p) = showsPrec n p--instance Storable (DevicePtr a) where- sizeOf _ = sizeOf (undefined :: Ptr a)- alignment _ = alignment (undefined :: Ptr a)- peek p = DevicePtr `fmap` peek (castPtr p)- poke p v = poke (castPtr p) (useDevicePtr v)----- |--- A reference to page-locked host memory.------ A 'HostPtr' is just a plain 'Ptr', but the memory has been allocated by CUDA--- into page locked memory. This means that the data can be copied to the GPU--- via DMA (direct memory access). Note that the use of the system function--- `mlock` is not sufficient here --- the CUDA version ensures that the--- /physical/ address stays this same, not just the virtual address.------ To copy data into a 'HostPtr' array, you may use for example 'withHostPtr'--- together with 'Foreign.Marshal.Array.copyArray' or--- 'Foreign.Marshal.Array.moveArray'.----newtype HostPtr a = HostPtr { useHostPtr :: Ptr a }- deriving (Eq,Ord)--instance Show (HostPtr a) where- showsPrec n (HostPtr p) = showsPrec n p--instance Storable (HostPtr a) where- sizeOf _ = sizeOf (undefined :: Ptr a)- alignment _ = alignment (undefined :: Ptr a)- peek p = HostPtr `fmap` peek (castPtr p)- poke p v = poke (castPtr p) (useHostPtr v)-------------------------------------------------------------------------------------- Events------------------------------------------------------------------------------------- |--- Events are markers that can be inserted into the CUDA execution stream and--- later queried.----newtype Event = Event { useEvent :: {# type CUevent #}}- deriving (Eq, Show)---- |--- Event creation flags----{# enum CUevent_flags as EventFlag- { underscoreToCase }- with prefix="CU_EVENT" deriving (Eq, Show, Bounded) #}---- |--- Possible option flags for waiting for events----data WaitFlag-instance Enum WaitFlag where-#ifdef USE_EMPTY_CASE- toEnum x = case x of {}- fromEnum x = case x of {}-#endif-------------------------------------------------------------------------------------- Stream management------------------------------------------------------------------------------------- |--- A processing stream. All operations in a stream are synchronous and executed--- in sequence, but operations in different non-default streams may happen--- out-of-order or concurrently with one another.------ Use 'Event's to synchronise operations between streams.----newtype Stream = Stream { useStream :: {# type CUstream #}}- deriving (Eq, Show)----- |--- Priority of an execution stream. Work submitted to a higher priority--- stream may preempt execution of work already executing in a lower--- priority stream. Lower numbers represent higher priorities.----type StreamPriority = Int---- |--- Possible option flags for stream initialisation. Dummy instance until the API--- exports actual option values.----data StreamFlag-instance Enum StreamFlag where-#ifdef USE_EMPTY_CASE- toEnum x = case x of {}- fromEnum x = case x of {}-#endif---- |--- The main execution stream. No operations overlap with operations in the--- default stream.----{-# INLINE defaultStream #-}-defaultStream :: Stream-defaultStream = Stream nullPtr-
Setup.hs view
@@ -1,18 +1,32 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE TemplateHaskell #-} +-- The MIN_VERSION_Cabal macro was introduced with Cabal-1.24 (??)+#ifndef MIN_VERSION_Cabal+#define MIN_VERSION_Cabal(major1,major2,minor) 0+#endif+ import Distribution.PackageDescription import Distribution.PackageDescription.Parse import Distribution.Simple import Distribution.Simple.BuildPaths import Distribution.Simple.Command-import Distribution.Simple.Program.Db import Distribution.Simple.LocalBuildInfo import Distribution.Simple.PreProcess hiding ( ppC2hs ) import Distribution.Simple.Program+import Distribution.Simple.Program.Db+import Distribution.Simple.Program.Find import Distribution.Simple.Setup-import Distribution.Simple.Utils+import Distribution.Simple.Utils hiding ( isInfixOf ) import Distribution.System import Distribution.Verbosity +#if MIN_VERSION_Cabal(1,25,0)+import Distribution.PackageDescription.PrettyPrint+import Distribution.Version+#endif+ import Control.Exception import Control.Monad import Data.Function@@ -473,9 +487,14 @@ findProgram :: Verbosity -> FilePath -> IO (Maybe FilePath) findProgram verbosity prog = do result <- findProgramOnSearchPath verbosity defaultProgramSearchPath prog- case result of- Nothing -> return Nothing- Just (path,_) -> return (Just path)+#if MIN_VERSION_Cabal(1,25,0)+ return (fmap fst result)+#else+ $( case withinRange cabalVersion (orLaterVersion (Version [1,24] [])) of+ True -> [| return (fmap fst result) |]+ False -> [| return result |]+ )+#endif -- Reads user-provided `cuda.buildinfo` if present, otherwise loads `cuda.buildinfo.generated`@@ -506,8 +525,13 @@ -- -- Everything below copied from Distribution.Simple.PreProcess --+#if MIN_VERSION_Cabal(1,25,0)+ppC2hs :: BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor+ppC2hs bi lbi _clbi+#else ppC2hs :: BuildInfo -> LocalBuildInfo -> PreProcessor ppC2hs bi lbi+#endif = PreProcessor { platformIndependent = False, runPreProcessor = \(inBaseDir, inRelativeFile)@@ -541,7 +565,15 @@ -- FIXME: this forces GHC's crazy 4.8.2 -> 408 convention on all the other -- compilers. Check if that's really what they want. versionInt :: Version -> String-versionInt (Version { versionBranch = [] }) = "1"-versionInt (Version { versionBranch = [n] }) = show n-versionInt (Version { versionBranch = n1:n2:_ }) = printf "%d%02d" n1 n2+versionInt v =+ case versionBranch v of+ [] -> "1"+ [n] -> show n+ n1:n2:_ -> printf "%d%02d" n1 n2+++#if MIN_VERSION_Cabal(1,25,0)+versionBranch :: Version -> [Int]+versionBranch = versionNumbers+#endif
cuda.cabal view
@@ -1,5 +1,5 @@ Name: cuda-Version: 0.7.5.0+Version: 0.7.5.1 Synopsis: FFI binding to the CUDA interface for programming NVIDIA GPUs Description: The CUDA library provides a direct, general purpose C-like SPMD programming@@ -24,10 +24,10 @@ . [/NOTES:/] .- The setup script for this package requires at least Cabal-1.24. To upgrade,+ The setup script for this package requires at least Cabal-1.22. To upgrade, execute one of: .- * cabal users: @cabal install Cabal --constraint="Cabal >= 1.24"@+ * cabal users: @cabal install Cabal --constraint="Cabal >= 1.22"@ . * stack users: @stack setup --upgrade-cabal@ .@@ -52,7 +52,7 @@ Homepage: https://github.com/tmcdonell/cuda Bug-reports: https://github.com/tmcdonell/cuda/issues Category: Foreign-Cabal-version: >= 1.24+Cabal-version: >= 1.22 Tested-with: GHC >= 7.6 Build-type: Custom@@ -67,11 +67,12 @@ custom-setup setup-depends: base >= 4.6- , Cabal >= 1.24+ , Cabal >= 1.22 , directory >= 1.0 , filepath >= 1.0 Library+ hs-source-dirs: src Exposed-Modules: Foreign.CUDA Foreign.CUDA.Ptr Foreign.CUDA.Types@@ -110,6 +111,7 @@ Foreign.CUDA.Driver.Utils Other-modules: Foreign.CUDA.Internal.C2HS+ Text.Show.Describe Include-dirs: . C-sources: cbits/stubs.c@@ -147,7 +149,7 @@ source-repository this type: git location: https://github.com/tmcdonell/cuda- tag: 0.7.5.0+ tag: 0.7.5.1 -- vim: nospell
examples/src/deviceQueryDrv/DeviceQuery.hs view
@@ -80,11 +80,7 @@ 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"+ $ text (describe computeMode) showFreq :: Integral i => i -> String
+ src/Foreign/CUDA.hs view
@@ -0,0 +1,19 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Top level bindings. By default, expose the C-for-CUDA runtime API bindings,+-- as they are slightly more user friendly.+--+--------------------------------------------------------------------------------++module Foreign.CUDA (++ module Foreign.CUDA.Runtime++) where++import Foreign.CUDA.Runtime+
+ src/Foreign/CUDA/Analysis.hs view
@@ -0,0 +1,20 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Analysis+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Meta-module exporting CUDA analysis routines+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Analysis (++ module Foreign.CUDA.Analysis.Device,+ module Foreign.CUDA.Analysis.Occupancy++) where++import Foreign.CUDA.Analysis.Device+import Foreign.CUDA.Analysis.Occupancy+
+ src/Foreign/CUDA/Analysis/Device.chs view
@@ -0,0 +1,196 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Analysis.Device+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Common device functions+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Analysis.Device (++ Compute(..), ComputeMode(..),+ DeviceProperties(..), DeviceResources(..), Allocation(..), PCI(..),+ deviceResources,+ describe++) where++#include "cbits/stubs.h"++import Data.Int+import Text.Show.Describe++import Debug.Trace+++-- |+-- The compute mode the device is currently in+--+{# enum CUcomputemode as ComputeMode+ { underscoreToCase }+ with prefix="CU_COMPUTEMODE" deriving (Eq, Show) #}++instance Describe ComputeMode where+ describe Default = "Multiple contexts are allowed on the device simultaneously"+#if CUDA_VERSION < 8000+ describe Exclusive = "Only one context used by a single thread can be present on this device at a time"+#endif+ describe Prohibited = "No contexts can be created on this device at this time"+ describe ExclusiveProcess = "Only one context used by a single process can be present on this device at a time"+++-- |+-- GPU compute capability, major and minor revision number respectively.+--+data Compute = Compute !Int !Int+ deriving Eq++instance Show Compute where+ show (Compute major minor) = show major ++ "." ++ show minor++instance Ord Compute where+ compare (Compute m1 n1) (Compute m2 n2) =+ case compare m1 m2 of+ EQ -> compare n1 n2+ x -> x++{--+cap :: Int -> Int -> Double+cap a 0 = fromIntegral a+cap a b = let a' = fromIntegral a in+ let b' = fromIntegral b in+ a' + b' / max 10 (10^ ((ceiling . logBase 10) b' :: Int))+--}++-- |+-- The properties of a compute device+--+data DeviceProperties = DeviceProperties+ {+ deviceName :: !String -- ^ Identifier+ , computeCapability :: !Compute -- ^ Supported compute capability+ , totalGlobalMem :: !Int64 -- ^ Available global memory on the device in bytes+ , totalConstMem :: !Int64 -- ^ Available constant memory on the device in bytes+ , sharedMemPerBlock :: !Int64 -- ^ Available shared memory per block in bytes+ , regsPerBlock :: !Int -- ^ 32-bit registers per block+ , warpSize :: !Int -- ^ Warp size in threads (SIMD width)+ , maxThreadsPerBlock :: !Int -- ^ Maximum number of threads per block+#if CUDA_VERSION >= 4000+ , maxThreadsPerMultiProcessor :: !Int -- ^ Maximum number of threads per multiprocessor+#endif+ , maxBlockSize :: !(Int,Int,Int) -- ^ Maximum size of each dimension of a block+ , maxGridSize :: !(Int,Int,Int) -- ^ Maximum size of each dimension of a grid+#if CUDA_VERSION >= 3000+ , maxTextureDim1D :: !Int -- ^ Maximum texture dimensions+ , maxTextureDim2D :: !(Int,Int)+ , maxTextureDim3D :: !(Int,Int,Int)+#endif+ , clockRate :: !Int -- ^ Clock frequency in kilohertz+ , multiProcessorCount :: !Int -- ^ Number of multiprocessors on the device+ , memPitch :: !Int64 -- ^ Maximum pitch in bytes allowed by memory copies+#if CUDA_VERSION >= 4000+ , memBusWidth :: !Int -- ^ Global memory bus width in bits+ , memClockRate :: !Int -- ^ Peak memory clock frequency in kilohertz+#endif+ , textureAlignment :: !Int64 -- ^ Alignment requirement for textures+ , computeMode :: !ComputeMode+ , deviceOverlap :: !Bool -- ^ Device can concurrently copy memory and execute a kernel+#if CUDA_VERSION >= 3000+ , concurrentKernels :: !Bool -- ^ Device can possibly execute multiple kernels concurrently+ , eccEnabled :: !Bool -- ^ Device supports and has enabled error correction+#endif+#if CUDA_VERSION >= 4000+ , asyncEngineCount :: !Int -- ^ Number of asynchronous engines+ , cacheMemL2 :: !Int -- ^ Size of the L2 cache in bytes+ , pciInfo :: !PCI -- ^ PCI device information for the device+ , tccDriverEnabled :: !Bool -- ^ Whether this is a Tesla device using the TCC driver+#endif+ , kernelExecTimeoutEnabled :: !Bool -- ^ Whether there is a runtime limit on kernels+ , integrated :: !Bool -- ^ As opposed to discrete+ , canMapHostMemory :: !Bool -- ^ Device can use pinned memory+#if CUDA_VERSION >= 4000+ , unifiedAddressing :: !Bool -- ^ Device shares a unified address space with the host+#endif+#if CUDA_VERSION >= 5050+ , streamPriorities :: !Bool -- ^ Device supports stream priorities+#endif+#if CUDA_VERSION >= 6000+ , globalL1Cache :: !Bool -- ^ Device supports caching globals in L1 cache+ , localL1Cache :: !Bool -- ^ Device supports caching locals in L1 cache+ , managedMemory :: !Bool -- ^ Device supports allocating managed memory on this system+ , multiGPUBoard :: !Bool -- ^ Device is on a multi-GPU board+ , multiGPUBoardGroupID :: !Int -- ^ Unique identifier for a group of devices associated with the same board+#endif+ }+ deriving (Show)+++data PCI = PCI+ {+ busID :: !Int, -- ^ PCI bus ID of the device+ deviceID :: !Int, -- ^ PCI device ID+ domainID :: !Int -- ^ PCI domain ID+ }+ deriving (Show)+++-- GPU Hardware Resources+--+data Allocation = Warp | Block+data DeviceResources = DeviceResources+ {+ threadsPerWarp :: !Int, -- ^ Warp size+ threadsPerMP :: !Int, -- ^ Maximum number of in-flight threads on a multiprocessor+ threadBlocksPerMP :: !Int, -- ^ Maximum number of thread blocks resident on a multiprocessor+ warpsPerMP :: !Int, -- ^ Maximum number of in-flight warps per multiprocessor+ coresPerMP :: !Int, -- ^ Number of SIMD arithmetic units per multiprocessor+ sharedMemPerMP :: !Int, -- ^ Total amount of shared memory per multiprocessor (bytes)+ sharedMemAllocUnit :: !Int, -- ^ Shared memory allocation unit size (bytes)+ regFileSize :: !Int, -- ^ Total number of registers in a multiprocessor+ regAllocUnit :: !Int, -- ^ Register allocation unit size+ regAllocWarp :: !Int, -- ^ Register allocation granularity for warps+ regPerThread :: !Int, -- ^ Maximum number of registers per thread+ allocation :: !Allocation -- ^ How multiprocessor resources are divided+ }+++-- |+-- Extract some additional hardware resource limitations for a given device.+--+deviceResources :: DeviceProperties -> DeviceResources+deviceResources = resources . computeCapability+ where+ -- This is mostly extracted from tables in the CUDA occupancy calculator.+ --+ resources compute = case compute of+ Compute 1 0 -> DeviceResources 32 768 8 24 8 16384 512 8192 256 2 124 Block -- Tesla G80+ Compute 1 1 -> DeviceResources 32 768 8 24 8 16384 512 8192 256 2 124 Block -- Tesla G8x+ Compute 1 2 -> DeviceResources 32 1024 8 32 8 16384 512 16384 512 2 124 Block -- Tesla G9x+ Compute 1 3 -> DeviceResources 32 1024 8 32 8 16384 512 16384 512 2 124 Block -- Tesla GT200+ Compute 2 0 -> DeviceResources 32 1536 8 48 32 49152 128 32768 64 2 63 Warp -- Fermi GF100+ Compute 2 1 -> DeviceResources 32 1536 8 48 48 49152 128 32768 64 2 63 Warp -- Fermi GF10x+ Compute 3 0 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 63 Warp -- Kepler GK10x+ Compute 3 2 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 255 Warp -- Jetson TK1+ Compute 3 5 -> DeviceResources 32 2048 16 64 192 49152 256 65536 256 4 255 Warp -- Kepler GK11x+ Compute 3 7 -> DeviceResources 32 2048 16 64 192 114688 256 131072 256 4 266 Warp -- Kepler GK21x+ Compute 5 0 -> DeviceResources 32 2048 32 64 128 65536 256 65536 256 4 255 Warp -- Maxwell GM10x+ Compute 5 2 -> DeviceResources 32 2048 32 64 128 98304 256 65536 256 4 255 Warp -- Maxwell GM20x+ Compute 5 3 -> DeviceResources 32 2048 32 64 128 65536 256 65536 256 4 255 Warp -- Maxwell GM20B+ Compute 6 0 -> DeviceResources 32 2048 32 64 64 65536 256 65536 256 4 255 Warp -- Pascal GP100 (?)+ Compute 6 1 -> DeviceResources 32 2048 32 64 128 98304 256 65536 256 4 255 Warp -- Pascal GP10x (?)+ Compute 6 2 -> DeviceResources 32 2048 32 64 128 65536 256 65536 256 4 255 Warp -- Pascal (?)++ -- Something might have gone wrong, or the library just needs to be+ -- updated for the next generation of hardware, in which case we just want+ -- to pick a sensible default and carry on.+ --+ -- This is slightly dodgy as the warning message is coming from pure code.+ -- However, it should be OK because all library functions run in IO, so it+ -- is likely the user code is as well.+ --+ _ -> trace warning $ resources (Compute 3 0)+ where warning = unlines [ "*** Warning: Unknown CUDA device compute capability: " ++ show compute+ , "*** Please submit a bug report at https://github.com/tmcdonell/cuda/issues" ]+
+ src/Foreign/CUDA/Analysis/Occupancy.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE BangPatterns #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Analysis.Occupancy+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Occupancy calculations for CUDA kernels+--+-- <http://developer.download.nvidia.com/compute/cuda/3_0/sdk/docs/CUDA_Occupancy_calculator.xls>+--+-- /Determining Registers Per Thread and Shared Memory Per Block/+--+-- To determine the number of registers used per thread in your kernel, simply+-- compile the kernel code using the option+--+-- > --ptxas-options=-v+--+-- to nvcc. This will output information about register, local memory, shared+-- memory, and constant memory usage for each kernel in the @.cu@ file.+-- Alternatively, you can compile with the @-cubin@ option to nvcc. This will+-- generate a @.cubin@ file, which you can open in a text editor. Look for the+-- @code@ section with your kernel's name. Within the curly braces (@{ ... }@)+-- for that code block, you will see a line with @reg = X@, where @x@ is the+-- number of registers used by your kernel. You can also see the amount of+-- shared memory used as @smem = Y@. However, if your kernel declares any+-- external shared memory that is allocated dynamically, you will need to add+-- the number in the @.cubin@ file to the amount you dynamically allocate at run+-- time to get the correct shared memory usage.+--+-- /Notes About Occupancy/+--+-- Higher occupancy does not necessarily mean higher performance. If a kernel+-- is not bandwidth bound, then increasing occupancy will not necessarily+-- increase performance. If a kernel invocation is already running at least one+-- thread block per multiprocessor in the GPU, and it is bottlenecked by+-- computation and not by global memory accesses, then increasing occupancy may+-- have no effect. In fact, making changes just to increase occupancy can have+-- other effects, such as additional instructions, spills to local memory (which+-- is off chip), divergent branches, etc. As with any optimization, you should+-- experiment to see how changes affect the *wall clock time* of the kernel+-- execution. For bandwidth bound applications, on the other hand, increasing+-- occupancy can help better hide the latency of memory accesses, and therefore+-- improve performance.+--+--------------------------------------------------------------------------------+++module Foreign.CUDA.Analysis.Occupancy (++ Occupancy(..),+ occupancy, optimalBlockSize, optimalBlockSizeOf, maxResidentBlocks,+ incPow2, incWarp, decPow2, decWarp++) where++import Data.Ord+import Data.List++import Foreign.CUDA.Analysis.Device+++-- GPU Occupancy per multiprocessor+--+data Occupancy = Occupancy+ {+ activeThreads :: !Int, -- ^ Active threads per multiprocessor+ activeThreadBlocks :: !Int, -- ^ Active thread blocks per multiprocessor+ activeWarps :: !Int, -- ^ Active warps per multiprocessor+ occupancy100 :: !Double -- ^ Occupancy of each multiprocessor (percent)+ }+ deriving (Eq, Ord, Show)+++-- |+-- Calculate occupancy data for a given GPU and kernel resource usage+--+{-# INLINEABLE occupancy #-}+occupancy+ :: DeviceProperties -- ^ Properties of the card in question+ -> Int -- ^ Threads per block+ -> Int -- ^ Registers per thread+ -> Int -- ^ Shared memory per block (bytes)+ -> Occupancy+occupancy !dev !thds !regs !smem+ = Occupancy at ab aw oc+ where+ at = ab * thds+ aw = ab * warps+ ab = minimum [limitWarpBlock, limitRegMP, limitSMemMP]+ oc = 100 * fromIntegral aw / fromIntegral (warpsPerMP gpu)++ regs' = 1 `max` regs+ smem' = 1 `max` smem++ ceiling' = ceiling :: Double -> Int+ ceilingBy x s = s * ceiling' (fromIntegral x / fromIntegral s)++ -- Physical resources+ --+ gpu = deviceResources dev++ -- Allocation per thread block+ --+ warps = ceiling' (fromIntegral thds / fromIntegral (threadsPerWarp gpu))+ sharedMem = ceilingBy smem' (sharedMemAllocUnit gpu)+ registers = case allocation gpu of+ Block -> (warps `ceilingBy` regAllocWarp gpu * regs' * threadsPerWarp gpu) `ceilingBy` regAllocUnit gpu+ Warp -> warps * ceilingBy (regs' * threadsPerWarp gpu) (regAllocUnit gpu)++ -- Maximum thread blocks per multiprocessor+ --+ limitWarpBlock = threadBlocksPerMP gpu `min` (warpsPerMP gpu `div` warps)+ limitRegMP = threadBlocksPerMP gpu `min` (regFileSize gpu `div` registers)+ limitSMemMP = threadBlocksPerMP gpu `min` (sharedMemPerMP gpu `div` sharedMem)+++-- |+-- Optimise multiprocessor occupancy as a function of thread block size and+-- resource usage. This returns the smallest satisfying block size in increments+-- of a single warp.+--+{-# INLINEABLE optimalBlockSize #-}+optimalBlockSize+ :: DeviceProperties -- ^ Architecture to optimise for+ -> (Int -> Int) -- ^ Register count as a function of thread block size+ -> (Int -> Int) -- ^ Shared memory usage (bytes) as a function of thread block size+ -> (Int, Occupancy)+optimalBlockSize dev = optimalBlockSizeOf dev (decWarp dev)+++-- |+-- As 'optimalBlockSize', but with a generator that produces the specific thread+-- block sizes that should be tested. The generated list can produce values in+-- any order, but the last satisfying block size will be returned. Hence, values+-- should be monotonically decreasing to return the smallest block size yielding+-- maximum occupancy, and vice-versa.+--+{-# INLINEABLE optimalBlockSizeOf #-}+optimalBlockSizeOf+ :: DeviceProperties -- ^ Architecture to optimise for+ -> [Int] -- ^ Thread block sizes to consider+ -> (Int -> Int) -- ^ Register count as a function of thread block size+ -> (Int -> Int) -- ^ Shared memory usage (bytes) as a function of thread block size+ -> (Int, Occupancy)+optimalBlockSizeOf !dev !threads !freg !fsmem+ = maximumBy (comparing (occupancy100 . snd))+ $ [ (t, occupancy dev t (freg t) (fsmem t)) | t <- threads ]+++-- | Increments in powers-of-two, over the range of supported thread block sizes+-- for the given device.+--+{-# INLINEABLE incPow2 #-}+incPow2 :: DeviceProperties -> [Int]+incPow2 !dev = map ((2::Int)^) [lb, lb+1 .. ub]+ where+ round' = round :: Double -> Int+ lb = round' . logBase 2 . fromIntegral $ warpSize dev+ ub = round' . logBase 2 . fromIntegral $ maxThreadsPerBlock dev++-- | Decrements in powers-of-two, over the range of supported thread block sizes+-- for the given device.+--+{-# INLINEABLE decPow2 #-}+decPow2 :: DeviceProperties -> [Int]+decPow2 !dev = map ((2::Int)^) [ub, ub-1 .. lb]+ where+ round' = round :: Double -> Int+ lb = round' . logBase 2 . fromIntegral $ warpSize dev+ ub = round' . logBase 2 . fromIntegral $ maxThreadsPerBlock dev++-- | Decrements in the warp size of the device, over the range of supported+-- thread block sizes.+--+{-# INLINEABLE decWarp #-}+decWarp :: DeviceProperties -> [Int]+decWarp !dev = [block, block-warp .. warp]+ where+ !warp = warpSize dev+ !block = maxThreadsPerBlock dev++-- | Increments in the warp size of the device, over the range of supported+-- thread block sizes.+--+{-# INLINEABLE incWarp #-}+incWarp :: DeviceProperties -> [Int]+incWarp !dev = [warp, 2*warp .. block]+ where+ warp = warpSize dev+ block = maxThreadsPerBlock dev+++-- |+-- Determine the maximum number of CTAs that can be run simultaneously for a+-- given kernel / device combination.+--+{-# INLINEABLE maxResidentBlocks #-}+maxResidentBlocks+ :: DeviceProperties -- ^ Properties of the card in question+ -> Int -- ^ Threads per block+ -> Int -- ^ Registers per thread+ -> Int -- ^ Shared memory per block (bytes)+ -> Int -- ^ Maximum number of resident blocks+maxResidentBlocks !dev !thds !regs !smem =+ multiProcessorCount dev * activeThreadBlocks (occupancy dev thds regs smem)+
+ src/Foreign/CUDA/Driver.hs view
@@ -0,0 +1,238 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- This module defines an interface to the CUDA driver API. The Driver API+-- is a lower-level interface to CUDA devices than that provided by the+-- Runtime API. Using the Driver API, the programmer must deal explicitly+-- with operations such as initialisation, context management, and loading+-- (kernel) modules. Although more difficult to use initially, the Driver+-- API provides more control over how CUDA is used. Furthermore, since it+-- does not require compiling and linking the program with 'nvcc', the+-- Driver API provides better inter-language compatibility.+--+-- The following is a short tutorial on using the Driver API. The steps can+-- be copied into a file, or run directly in @ghci@, in which case @ghci@+-- should be launched with the option @-fno-ghci-sandbox@. This is because+-- CUDA maintains CPU-local state, so operations should always be run from+-- a bound thread.+--+--+-- [/Using the Driver API/]+--+-- Before any operation can be performed, the Driver API must be+-- initialised:+--+-- >>> import Foreign.CUDA.Driver+-- >>> initialise []+--+-- Next, we must select a GPU that we will execute operations on. Each GPU+-- is assigned a unique identifier (beginning at zero). We can get a handle+-- to a compute device at a given ordinal using the 'device' operation.+-- Given a device handle, we can query the properties of that device using+-- 'props'. The number of available CUDA-capable devices is given via+-- 'count'. For example:+--+-- >>> count+-- 1+-- >>> dev0 <- device 0+-- >>> props dev0+-- DeviceProperties {deviceName = "GeForce GT 650M", computeCapability = 3.0, ...}+--+-- This package also includes the executable 'nvidia-device-query', which when+-- executed displays the key properties of all available devices. See+-- "Foreign.CUDA.Driver.Device" for additional operations to query the+-- capabilities or status of a device.+--+-- Once you have chosen a device to use, the next step is to create a CUDA+-- context. A context is associated with a particular device, and all+-- operations, such as memory allocation and kernel execution, take place+-- with respect to that context. For example, to 'create' a new execution+-- context on CUDA device 0:+--+-- >>> ctx <- create dev0 []+--+-- The second argument is a set of 'ContextFlag's which control how the+-- context behaves in various situations, for example, whether or not the+-- CPU should actively spin when waiting for results from the GPU+-- ('SchedSpin'), or to yield control to other threads instead+-- ('SchedYield').+--+-- The newly created context is now the /active/ context, and all+-- subsequent operations take place within that context. More than one+-- context can be created per device, but resources, such as memory+-- allocated in the GPU, are unique to each context. The module+-- "Foreign.CUDA.Driver.Context" contains operations for managing multiple+-- contexts. Some devices allow data to be shared between contexts without+-- copying, see "Foreign.CUDA.Driver.Context.Peer" for more information.+--+-- Once the context is no longer needed, it should be 'destroy'ed in order+-- to free up any resources that were allocated to it.+--+-- >>> destroy ctx+--+-- Each device also has a unique context which is used by the Runtime API.+-- This context can be accessed with the module+-- "Foreign.CUDA.Driver.Context.Primary".+--+--+-- [/Executing kernels onto the GPU/]+--+-- Once the Driver API is initialised and an execution context is created+-- on the GPU, we can begin to interact with it.+--+-- At an example, we'll step through executing the CUDA equivalent of the+-- following Haskell function, which element-wise adds the elements of two+-- arrays:+--+-- >>> vecAdd xs ys = zipWith (+) xs ys+--+-- The following CUDA kernel can be used to implement this on the GPU:+--+-- > extern "C" __global__ void vecAdd(float *xs, float *ys, float *zs, int N)+-- > {+-- > int ix = blockIdx.x * blockDim.x + threadIdx.x;+-- >+-- > if ( ix < N ) {+-- > zs[ix] = xs[ix] + ys[ix];+-- > }+-- > }+--+-- Here, the @__global__@ keyword marks the function as a kernel that+-- should be computed on the GPU in data parallel. When we execute this+-- function on the GPU, (at least) /N/ threads will execute /N/ individual+-- instances of the kernel function @vecAdd@. Each thread will operate on+-- a single element of each input array to create a single value in the+-- result. See the CUDA programming guide for more details.+--+-- We can save this to a file @vector_add.cu@, and compile it using @nvcc@+-- into a form that we can then load onto the GPU and execute:+--+-- > $ nvcc --ptx vector_add.cu+--+-- The module "Foreign.CUDA.Driver.Module" contains functions for loading+-- the resulting .ptx file (or .cubin files) into the running program.+--+-- >>> mdl <- loadFile "vector_add.ptx"+--+-- Once finished with the module, it is also a good idea to 'unload' it.+--+-- Modules may export kernel functions, global variables, and texture+-- references. Before we can execute our function, we need to look it up in+-- the module by name.+--+-- >>> vecAdd <- getFun mdl "vecAdd"+--+-- Given this reference to our kernel function, we are almost ready to+-- execute it on the device using 'launchKernel', but first, we must create+-- some data that we can execute the function on.+--+--+-- [/Transferring data to and from the GPU/]+--+-- GPUs typically have their own memory which is separate from the CPU's+-- memory, and we need to explicitly copy data back and forth between these+-- two regions. The module "Foreign.CUDA.Driver.Marshal" provides functions+-- for allocating memory on the GPU, and copying data between the CPU and+-- GPU, as well as directly between multiple GPUs.+--+-- For simplicity, we'll use standard Haskell lists for our input and+-- output data structure. Note however that this will have significantly+-- lower effective bandwidth than reading a single contiguous region of+-- memory, so for most practical purposes you will want to use some kind of+-- unboxed array.+--+-- >>> let xs = [1..1024] :: [Float]+-- >>> let ys = [2,4..2048] :: [Float]+--+-- In CUDA, like C, all memory management is explicit, and arrays on the+-- device must be explicitly allocated and freed. As mentioned previously,+-- data transfer is also explicit. However, we do provide convenience+-- functions for combined allocation and marshalling, as well as bracketed+-- operations.+--+-- >>> xs_dev <- newListArray xs+-- >>> ys_dev <- newListArray ys+-- >>> zs_dev <- mallocArray 1024 :: IO (DevicePtr Float)+--+-- After executing the kernel (see next section), we transfer the result+-- back to the host, and free the memory that was allocated on the GPU.+--+-- >>> zs <- peekListArray 1024 zs_dev+-- >>> free xs_dev+-- >>> free ys_dev+-- >>> free zs_dev+--+--+-- [/Piecing it all together/]+--+-- Finally, we have everything in place to execute our operation on the+-- GPU. Launching a kernel on the GPU consists of creating many threads on+-- the GPU which all execute the same function, and each thread has+-- a unique identifier in the grid/block hierarchy which can be used to+-- identify exactly which element this thread should process (the+-- @blockIdx@ and @threadIdx@ parameters that we saw earlier,+-- respectively).+--+-- To execute our function, we will use a grid of 4 blocks, each containing+-- 256 threads. Thus, a total of 1024 threads will be launched, which will+-- each compute a single element of the output array (recall that our input+-- arrays each have 1024 elements). The module+-- "Foreign.CUDA.Analysis.Occupancy" contains functions to help determine+-- the ideal thread block size for a given kernel and GPU combination.+--+-- >>> launchKernel vecAdd (4,1,1) (256,1,1) 0 Nothing [VArg xs_dev, VArg ys_dev, VArg zs_dev, IArg 1024]+--+-- Note that kernel execution is asynchronous, so we should also wait for+-- the operation to complete before attempting to read the results back.+--+-- >>> sync+--+-- And that's it!+--+--+-- [/Next steps/]+--+-- As mentioned at the end of the previous section, kernels on the GPU are+-- executed asynchronously with respect to the host, and other operations+-- such as data transfers can also be executed asynchronously. This allows+-- the CPU to continue doing other work while the GPU is busy.+-- 'Foreign.CUDA.Driver.Event.Event's can be used to check whether an+-- operation has completed yet.+--+-- It is also possible to execute multiple kernels or data transfers+-- concurrently with each other, by assigning those operations to different+-- execution 'Foreign.CUDA.Driver.Stream.Stream's. Used in conjunction with+-- 'Foreign.CUDA.Driver.Event.Event's, operations will be scheduled+-- efficiently only once all dependencies (in the form of+-- 'Foreign.CUDA.Driver.Event.Event's) have been cleared.+--+-- See "Foreign.CUDA.Driver.Event" and "Foreign.CUDA.Driver.Stream" for+-- more information on this topic.+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver (++ module Foreign.CUDA.Ptr,+ module Foreign.CUDA.Driver.Context,+ module Foreign.CUDA.Driver.Device,+ module Foreign.CUDA.Driver.Error,+ module Foreign.CUDA.Driver.Exec,+ module Foreign.CUDA.Driver.Marshal,+ module Foreign.CUDA.Driver.Module,+ module Foreign.CUDA.Driver.Utils++) where++import Foreign.CUDA.Ptr+import Foreign.CUDA.Driver.Context hiding ( useContext, device )+import Foreign.CUDA.Driver.Device hiding ( useDevice )+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Exec+import Foreign.CUDA.Driver.Marshal hiding ( useDeviceHandle, peekDeviceHandle )+import Foreign.CUDA.Driver.Module+import Foreign.CUDA.Driver.Utils+
+ src/Foreign/CUDA/Driver/Context.hs view
@@ -0,0 +1,23 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Context+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- Context management for low-level driver interface+--+--------------------------------------------------------------------------------+++module Foreign.CUDA.Driver.Context (++ module Foreign.CUDA.Driver.Context.Base,+ module Foreign.CUDA.Driver.Context.Config,+ module Foreign.CUDA.Driver.Context.Peer,++) where++import Foreign.CUDA.Driver.Context.Base+import Foreign.CUDA.Driver.Context.Config+import Foreign.CUDA.Driver.Context.Peer+
+ src/Foreign/CUDA/Driver/Context/Base.chs view
@@ -0,0 +1,241 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Context.Base+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- Context management for the low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Context.Base (++ -- * Context Management+ Context(..), ContextFlag(..),+ create, destroy, device, pop, push, sync, get, set,++ -- Deprecated in CUDA-4.0+ attach, detach,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Device ( Device(..) )+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad ( liftM )+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A device context+--+newtype Context = Context { useContext :: {# type CUcontext #}}+ deriving (Eq, Show)+++-- |+-- Context creation flags+--+{# enum CUctx_flags as ContextFlag+ { underscoreToCase }+ with prefix="CU_CTX" deriving (Eq, Show, Bounded) #}+++#if CUDA_VERSION >= 4000+{-# DEPRECATED attach, detach "as of CUDA-4.0" #-}+{-# DEPRECATED BlockingSync "use SchedBlockingSync instead" #-}+#endif+++--------------------------------------------------------------------------------+-- Context management+--------------------------------------------------------------------------------++-- |+-- Create a new CUDA context and associate it with the calling thread. The+-- context is created with a usage count of one, and the caller of 'create'+-- must call 'destroy' when done using the context. If a context is already+-- current to the thread, it is supplanted by the newly created context and+-- must be restored by a subsequent call to 'pop'.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g65dc0012348bc84810e2103a40d8e2cf>+--+{-# INLINEABLE create #-}+create :: Device -> [ContextFlag] -> IO Context+create !dev !flags = resultIfOk =<< cuCtxCreate flags dev++{-# INLINE cuCtxCreate #-}+{# fun unsafe cuCtxCreate+ { alloca- `Context' peekCtx*+ , combineBitMasks `[ContextFlag]'+ , useDevice `Device' } -> `Status' cToEnum #}+ where peekCtx = liftM Context . peek+++-- |+-- Increments the usage count of the context. API: no context flags are+-- currently supported, so this parameter must be empty.+--+{-# INLINEABLE attach #-}+attach :: Context -> [ContextFlag] -> IO ()+attach !ctx !flags = nothingIfOk =<< cuCtxAttach ctx flags++{-# INLINE cuCtxAttach #-}+{# fun unsafe cuCtxAttach+ { withCtx* `Context'+ , combineBitMasks `[ContextFlag]' } -> `Status' cToEnum #}+ where withCtx = with . useContext+++-- |+-- Detach the context, and destroy if no longer used+--+{-# INLINEABLE detach #-}+detach :: Context -> IO ()+detach !ctx = nothingIfOk =<< cuCtxDetach ctx++{-# INLINE cuCtxDetach #-}+{# fun unsafe cuCtxDetach+ { useContext `Context' } -> `Status' cToEnum #}+++-- |+-- Destroy the specified context, regardless of how many threads it is+-- current to. The context will be 'pop'ed from the current thread's+-- context stack, but if it is current on any other threads it will remain+-- current to those threads, and attempts to access it will result in an+-- error.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g27a365aebb0eb548166309f58a1e8b8e>+--+{-# INLINEABLE destroy #-}+destroy :: Context -> IO ()+destroy !ctx = nothingIfOk =<< cuCtxDestroy ctx++{-# INLINE cuCtxDestroy #-}+{# fun unsafe cuCtxDestroy+ { useContext `Context' } -> `Status' cToEnum #}+++-- |+-- Return the context bound to the calling CPU thread.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g8f13165846b73750693640fb3e8380d0>+--+{-# INLINEABLE get #-}+get :: IO (Maybe Context)+#if CUDA_VERSION < 4000+get = requireSDK 'get 4.0+#else+get = resultIfOk =<< cuCtxGetCurrent++{-# INLINE cuCtxGetCurrent #-}+{# fun unsafe cuCtxGetCurrent+ { alloca- `Maybe Context' peekCtx* } -> `Status' cToEnum #}+ where peekCtx = liftM (nothingIfNull Context) . peek+#endif+++-- |+-- Bind the specified context to the calling thread.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gbe562ee6258b4fcc272ca6478ca2a2f7>+--+{-# INLINEABLE set #-}+set :: Context -> IO ()+#if CUDA_VERSION < 4000+set _ = requireSDK 'set 4.0+#else+set !ctx = nothingIfOk =<< cuCtxSetCurrent ctx++{-# INLINE cuCtxSetCurrent #-}+{# fun unsafe cuCtxSetCurrent+ { useContext `Context' } -> `Status' cToEnum #}+#endif+++-- |+-- Return the device of the currently active context+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g4e84b109eba36cdaaade167f34ae881e>+--+{-# INLINEABLE device #-}+device :: IO Device+device = resultIfOk =<< cuCtxGetDevice++{-# INLINE cuCtxGetDevice #-}+{# fun unsafe cuCtxGetDevice+ { alloca- `Device' dev* } -> `Status' cToEnum #}+ where dev = liftM Device . peekIntConv+++-- |+-- Pop the current CUDA context from the CPU thread. The context may then+-- be attached to a different CPU thread by calling 'push'.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g2fac188026a062d92e91a8687d0a7902>+--+{-# INLINEABLE pop #-}+pop :: IO Context+pop = resultIfOk =<< cuCtxPopCurrent++{-# INLINE cuCtxPopCurrent #-}+{# fun unsafe cuCtxPopCurrent+ { alloca- `Context' peekCtx* } -> `Status' cToEnum #}+ where peekCtx = liftM Context . peek+++-- |+-- Push the given context onto the CPU's thread stack of current contexts.+-- The specified context becomes the CPU thread's current context, so all+-- operations that operate on the current context are affected.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gb02d4c850eb16f861fe5a29682cc90ba>+--+{-# INLINEABLE push #-}+push :: Context -> IO ()+push !ctx = nothingIfOk =<< cuCtxPushCurrent ctx++{-# INLINE cuCtxPushCurrent #-}+{# fun unsafe cuCtxPushCurrent+ { useContext `Context' } -> `Status' cToEnum #}+++-- |+-- Block until the device has completed all preceding requests. If the+-- context was created with the 'SchedBlockingSync' flag, the CPU thread+-- will block until the GPU has finished its work.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g7a54725f28d34b8c6299f0c6ca579616>+--+{-# INLINEABLE sync #-}+sync :: IO ()+sync = nothingIfOk =<< cuCtxSynchronize++{-# INLINE cuCtxSynchronize #-}+{# fun cuCtxSynchronize+ { } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Driver/Context/Config.chs view
@@ -0,0 +1,297 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Context.Config+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- Context configuration for the low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Context.Config (++ -- * Context configuration+ getFlags,++ -- ** Resource limits+ Limit(..),+ getLimit, setLimit,++ -- ** Cache+ Cache(..),+ getCache, setCache,++ -- ** Shared memory+ SharedMem(..),+ getSharedMem, setSharedMem,++ -- ** Streams+ StreamPriority,+ getStreamPriorityRange,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Context.Base+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS+import Foreign.CUDA.Types++-- System+import Control.Monad+import Foreign+import Foreign.C+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- Device limits flags+--+#if CUDA_VERSION < 3010+data Limit+#else+{# enum CUlimit_enum as Limit+ { underscoreToCase }+ with prefix="CU_LIMIT" deriving (Eq, Show) #}+#endif+++-- |+-- Device cache configuration preference+--+#if CUDA_VERSION < 3020+data Cache+#else+{# enum CUfunc_cache_enum as Cache+ { underscoreToCase }+ with prefix="CU_FUNC_CACHE" deriving (Eq, Show) #}+#endif+++-- |+-- Device shared memory configuration preference+--+#if CUDA_VERSION < 4020+data SharedMem+#else+{# enum CUsharedconfig as SharedMem+ { underscoreToCase }+ with prefix="CU_SHARED_MEM_CONFIG" deriving (Eq, Show) #}+#endif+++--------------------------------------------------------------------------------+-- Context configuration+--------------------------------------------------------------------------------++-- |+-- Return the flags that were used to create the current context.+--+-- Requires CUDA-7.0+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1gf81eef983c1e3b2ef4f166d7a930c86d>+--+{-# INLINEABLE getFlags #-}+getFlags :: IO [ContextFlag]+#if CUDA_VERSION < 7000+getFlags = requireSDK 'getFlags 7.0+#else+getFlags = resultIfOk =<< cuCtxGetFlags++{-# INLINE cuCtxGetFlags #-}+{# fun unsafe cuCtxGetFlags+ { alloca- `[ContextFlag]' peekFlags* } -> `Status' cToEnum #}+ where+ peekFlags = liftM extractBitMasks . peek+#endif+++-- |+-- Query compute 2.0 call stack limits.+--+-- Requires CUDA-3.1.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g9f2d47d1745752aa16da7ed0d111b6a8>+--+{-# INLINEABLE getLimit #-}+getLimit :: Limit -> IO Int+#if CUDA_VERSION < 3010+getLimit _ = requireSDK 'getLimit 3.1+#else+getLimit !l = resultIfOk =<< cuCtxGetLimit l++{-# INLINE cuCtxGetLimit #-}+{# fun unsafe cuCtxGetLimit+ { alloca- `Int' peekIntConv*+ , cFromEnum `Limit' } -> `Status' cToEnum #}+#endif+++-- |+-- Specify the size of the call stack, for compute 2.0 devices.+--+-- Requires CUDA-3.1.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g0651954dfb9788173e60a9af7201e65a>+--+{-# INLINEABLE setLimit #-}+setLimit :: Limit -> Int -> IO ()+#if CUDA_VERSION < 3010+setLimit _ _ = requireSDK 'setLimit 3.1+#else+setLimit !l !n = nothingIfOk =<< cuCtxSetLimit l n++{-# INLINE cuCtxSetLimit #-}+{# fun unsafe cuCtxSetLimit+ { cFromEnum `Limit'+ , cIntConv `Int' } -> `Status' cToEnum #}+#endif+++-- |+-- On devices where the L1 cache and shared memory use the same hardware+-- resources, this function returns the preferred cache configuration for+-- the current context.+--+-- Requires CUDA-3.2.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g40b6b141698f76744dea6e39b9a25360>+--+{-# INLINEABLE getCache #-}+getCache :: IO Cache+#if CUDA_VERSION < 3020+getCache = requireSDK 'getCache 3.2+#else+getCache = resultIfOk =<< cuCtxGetCacheConfig++{-# INLINE cuCtxGetCacheConfig #-}+{# fun unsafe cuCtxGetCacheConfig+ { alloca- `Cache' peekEnum* } -> `Status' cToEnum #}+#endif+++-- |+-- On devices where the L1 cache and shared memory use the same hardware+-- resources, this sets the preferred cache configuration for the current+-- context. This is only a preference.+--+-- Any function configuration set via+-- 'Foreign.CUDA.Driver.Exec.setCacheConfigFun' will be preferred over this+-- context-wide setting.+--+-- Requires CUDA-3.2.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g54699acf7e2ef27279d013ca2095f4a3>+--+{-# INLINEABLE setCache #-}+setCache :: Cache -> IO ()+#if CUDA_VERSION < 3020+setCache _ = requireSDK 'setCache 3.2+#else+setCache !c = nothingIfOk =<< cuCtxSetCacheConfig c++{-# INLINE cuCtxSetCacheConfig #-}+{# fun unsafe cuCtxSetCacheConfig+ { cFromEnum `Cache' } -> `Status' cToEnum #}+#endif+++-- |+-- Return the current size of the shared memory banks in the current+-- context. On devices with configurable shared memory banks,+-- 'setSharedMem' can be used to change the configuration, so that+-- subsequent kernel launches will by default us the new bank size. On+-- devices without configurable shared memory, this function returns the+-- fixed bank size of the hardware.+--+-- Requires CUDA-4.2+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g17153a1b8b8c756f7ab8505686a4ad74>+--+{-# INLINEABLE getSharedMem #-}+getSharedMem :: IO SharedMem+#if CUDA_VERSION < 4020+getSharedMem = requireSDK 'getSharedMem 4.2+#else+getSharedMem = resultIfOk =<< cuCtxGetSharedMemConfig++{-# INLINE cuCtxGetSharedMemConfig #-}+{# fun unsafe cuCtxGetSharedMemConfig+ { alloca- `SharedMem' peekEnum*+ } -> `Status' cToEnum #}+#endif+++-- |+-- On devices with configurable shared memory banks, this function will set+-- the context's shared memory bank size that will be used by default for+-- subsequent kernel launches.+--+-- Changing the shared memory configuration between launches may insert+-- a device synchronisation.+--+-- Shared memory bank size does not affect shared memory usage or kernel+-- occupancy, but may have major effects on performance. Larger bank sizes+-- allow for greater potential bandwidth to shared memory, but change the+-- kinds of accesses which result in bank conflicts.+--+-- Requires CUDA-4.2+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g2574235fa643f8f251bf7bc28fac3692>+--+{-# INLINEABLE setSharedMem #-}+setSharedMem :: SharedMem -> IO ()+#if CUDA_VERSION < 4020+setSharedMem _ = requireSDK 'setSharedMem 4.2+#else+setSharedMem !c = nothingIfOk =<< cuCtxSetSharedMemConfig c++{-# INLINE cuCtxSetSharedMemConfig #-}+{# fun unsafe cuCtxSetSharedMemConfig+ { cFromEnum `SharedMem' } -> `Status' cToEnum #}+#endif++++-- |+-- Returns the numerical values that correspond to the greatest and least+-- priority execution streams in the current context respectively. Stream+-- priorities follow the convention that lower numerical numbers correspond+-- to higher priorities. The range of meaningful stream priorities is given+-- by the inclusive range [greatestPriority,leastPriority].+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__CTX.html#group__CUDA__CTX_1g137920ab61a71be6ce67605b9f294091>+--+{-# INLINEABLE getStreamPriorityRange #-}+getStreamPriorityRange :: IO (StreamPriority, StreamPriority)+#if CUDA_VERSION < 5050+getStreamPriorityRange = requireSDK 'getStreamPriorityRange 5.5+#else+getStreamPriorityRange = do+ (r,l,h) <- cuCtxGetStreamPriorityRange+ resultIfOk (r, (h,l))++{-# INLINE cuCtxGetStreamPriorityRange #-}+{# fun unsafe cuCtxGetStreamPriorityRange+ { alloca- `Int' peekIntConv*+ , alloca- `Int' peekIntConv*+ }+ -> `Status' cToEnum #}+#endif+
+ src/Foreign/CUDA/Driver/Context/Peer.chs view
@@ -0,0 +1,131 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Context.Peer+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- Direct peer context access functions for the low-level driver interface.+--+-- Since: CUDA-4.0+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Context.Peer (++ -- * Peer Access+ PeerFlag,+ accessible, add, remove,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Context.Base ( Context(..) )+import Foreign.CUDA.Driver.Device ( Device(..) )+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- Possible option values for direct peer memory access+--+data PeerFlag+instance Enum PeerFlag where+#ifdef USE_EMPTY_CASE+ toEnum x = case x of {}+ fromEnum x = case x of {}+#endif+++--------------------------------------------------------------------------------+-- Peer access+--------------------------------------------------------------------------------++-- |+-- Queries if the first device can directly access the memory of the second. If+-- direct access is possible, it can then be enabled with 'add'.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g496bdaae1f632ebfb695b99d2c40f19e>+--+{-# INLINEABLE accessible #-}+accessible :: Device -> Device -> IO Bool+#if CUDA_VERSION < 4000+accessible _ _ = requireSDK 'accessible 4.0+#else+accessible !dev !peer = resultIfOk =<< cuDeviceCanAccessPeer dev peer++{-# INLINE cuDeviceCanAccessPeer #-}+{# fun unsafe cuDeviceCanAccessPeer+ { alloca- `Bool' peekBool*+ , useDevice `Device'+ , useDevice `Device' } -> `Status' cToEnum #}+#endif+++-- |+-- If the devices of both the current and supplied contexts support unified+-- addressing, then enable allocations in the supplied context to be accessible+-- by the current context.+--+-- Note that access is unidirectional, and in order to access memory in the+-- current context from the peer context, a separate symmetric call to+-- 'add' is required.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g0889ec6728e61c05ed359551d67b3f5a>+--+{-# INLINEABLE add #-}+add :: Context -> [PeerFlag] -> IO ()+#if CUDA_VERSION < 4000+add _ _ = requireSDK 'add 4.0+#else+add !ctx !flags = nothingIfOk =<< cuCtxEnablePeerAccess ctx flags++{-# INLINE cuCtxEnablePeerAccess #-}+{# fun unsafe cuCtxEnablePeerAccess+ { useContext `Context'+ , combineBitMasks `[PeerFlag]' } -> `Status' cToEnum #}+#endif+++-- |+-- Disable direct memory access from the current context to the supplied+-- peer context, and unregisters any registered allocations.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PEER__ACCESS.html#group__CUDA__PEER__ACCESS_1g5b4b6936ea868d4954ce4d841a3b4810>+--+{-# INLINEABLE remove #-}+remove :: Context -> IO ()+#if CUDA_VERSION < 4000+remove _ = requireSDK 'remave 4.0+#else+remove !ctx = nothingIfOk =<< cuCtxDisablePeerAccess ctx++{-# INLINE cuCtxDisablePeerAccess #-}+{# fun unsafe cuCtxDisablePeerAccess+ { useContext `Context' } -> `Status' cToEnum #}+#endif+
+ src/Foreign/CUDA/Driver/Context/Primary.chs view
@@ -0,0 +1,170 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Context.Primary+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Primary context management for low-level driver interface. The primary+-- context is unique per device and shared with the Runtime API. This+-- allows integration with other libraries using CUDA.+--+-- Since: CUDA-7.0+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Context.Primary (++ status, setup, reset, retain, release,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Context.Base+import Foreign.CUDA.Driver.Device+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Control.Exception+import Control.Monad+import Foreign+import Foreign.C+++--------------------------------------------------------------------------------+-- Primary context management+--------------------------------------------------------------------------------+++-- |+-- Get the status of the primary context. Returns whether the current+-- context is active, and the flags it was (or will be) created with.+--+-- Requires CUDA-7.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g65f3e018721b6d90aa05cfb56250f469>+--+{-# INLINEABLE status #-}+status :: Device -> IO (Bool, [ContextFlag])+#if CUDA_VERSION < 7000+status _ = requireSDK 'status 7.0+#else+status !dev =+ cuDevicePrimaryCtxGetState dev >>= \(rv, !flags, !active) ->+ case rv of+ Success -> return (active, flags)+ _ -> throwIO (ExitCode rv)++{# fun unsafe cuDevicePrimaryCtxGetState+ { useDevice `Device'+ , alloca- `[ContextFlag]' peekFlags*+ , alloca- `Bool' peekBool*+ } -> `Status' cToEnum #}+ where+ peekFlags = liftM extractBitMasks . peek+#endif+++-- |+-- Specify the flags that the primary context should be created with. Note+-- that this is an error if the primary context is already active.+--+-- Requires CUDA-7.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1gd779a84f17acdad0d9143d9fe719cfdf>+--+{-# INLINEABLE setup #-}+setup :: Device -> [ContextFlag] -> IO ()+#if CUDA_VERSION < 7000+setup _ _ = requireSDK 'setup 7.0+#else+setup !dev !flags = nothingIfOk =<< cuDevicePrimaryCtxSetFlags dev flags++{-# INLINE cuDevicePrimaryCtxSetFlags #-}+{# fun unsafe cuDevicePrimaryCtxSetFlags+ { useDevice `Device'+ , combineBitMasks `[ContextFlag]'+ } -> `Status' cToEnum #}+#endif+++-- |+-- Destroy all allocations and reset all state on the primary context of+-- the given device in the current process. Requires cuda-7.0+--+-- Requires CUDA-7.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g5d38802e8600340283958a117466ce12>+--+{-# INLINEABLE reset #-}+reset :: Device -> IO ()+#if CUDA_VERSION < 7000+reset _ = requireSDK 'reset 7.0+#else+reset !dev = nothingIfOk =<< cuDevicePrimaryCtxReset dev++{-# INLINE cuDevicePrimaryCtxReset #-}+{# fun unsafe cuDevicePrimaryCtxReset+ { useDevice `Device' } -> `Status' cToEnum #}+#endif+++-- |+-- Release the primary context on the given device. If there are no more+-- references to the primary context it will be destroyed, regardless of+-- how many threads it is current to.+--+-- Unlike 'Foreign.CUDA.Driver.Context.Base.pop' this does not pop the+-- context from the stack in any circumstances.+--+-- Requires CUDA-7.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1gf2a8bc16f8df0c88031f6a1ba3d6e8ad>+--+{-# INLINEABLE release #-}+release :: Device -> IO ()+#if CUDA_VERSION < 7000+release _ = requireSDK 'release 7.0+#else+release !dev = nothingIfOk =<< cuDevicePrimaryCtxRelease dev++{-# INLINE cuDevicePrimaryCtxRelease #-}+{# fun unsafe cuDevicePrimaryCtxRelease+ { useDevice `Device' } -> `Status' cToEnum #}+#endif+++-- |+-- Retain the primary context for the given device, creating it if+-- necessary, and increasing its usage count. The caller must call+-- 'release' when done using the context. Unlike+-- 'Foreign.CUDA.Driver.Context.Base.create' the newly retained context is+-- not pushed onto the stack.+--+-- Requires CUDA-7.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PRIMARY__CTX.html#group__CUDA__PRIMARY__CTX_1g9051f2d5c31501997a6cb0530290a300>+--+{-# INLINEABLE retain #-}+retain :: Device -> IO Context+#if CUDA_VERSION < 7000+retain _ = requireSDK 'retain 7.0+#else+retain !dev = resultIfOk =<< cuDevicePrimaryCtxRetain dev++{-# INLINE cuDevicePrimaryCtxRetain #-}+{# fun unsafe cuDevicePrimaryCtxRetain+ { alloca- `Context' peekCtx*+ , useDevice `Device'+ } -> `Status' cToEnum #}+ where+ peekCtx = liftM Context . peek+#endif+
+ src/Foreign/CUDA/Driver/Device.chs view
@@ -0,0 +1,403 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Device+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Device management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Device (++ -- * Device Management+ Device(..),+ DeviceProperties(..), DeviceAttribute(..), Compute(..), ComputeMode(..), InitFlag,+ initialise, capability, device, attribute, count, name, props, totalMem++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Analysis.Device+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad ( liftM )+import Control.Applicative+import Prelude+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A CUDA device+--+newtype Device = Device { useDevice :: {# type CUdevice #}}+ deriving (Eq, Show)+++-- |+-- Device attributes+--+{# enum CUdevice_attribute as DeviceAttribute+ { underscoreToCase+ , MAX as CU_DEVICE_ATTRIBUTE_MAX } -- ignore+ with prefix="CU_DEVICE_ATTRIBUTE" deriving (Eq, Show) #}+++#if CUDA_VERSION < 5000+{# pointer *CUdevprop as ^ foreign -> CUDevProp nocode #}++--+-- Properties of the compute device (internal helper).+-- Replaced by cuDeviceGetAttribute in CUDA-5.0 and later.+--+data CUDevProp = CUDevProp+ {+ cuMaxThreadsPerBlock :: !Int, -- Maximum number of threads per block+ cuMaxBlockSize :: !(Int,Int,Int), -- Maximum size of each dimension of a block+ cuMaxGridSize :: !(Int,Int,Int), -- Maximum size of each dimension of a grid+ cuSharedMemPerBlock :: !Int64, -- Shared memory available per block in bytes+ cuTotalConstMem :: !Int64, -- Constant memory available on device in bytes+ cuWarpSize :: !Int, -- Warp size in threads (SIMD width)+ cuMemPitch :: !Int64, -- Maximum pitch in bytes allowed by memory copies+ cuRegsPerBlock :: !Int, -- 32-bit registers available per block+ cuClockRate :: !Int, -- Clock frequency in kilohertz+ cuTextureAlignment :: !Int64 -- Alignment requirement for textures+ }+ deriving (Show)+++instance Storable CUDevProp where+ sizeOf _ = {#sizeof CUdevprop#}+ alignment _ = alignment (undefined :: Ptr ())++ poke _ _ = error "no instance for Foreign.Storable.poke DeviceProperties"+ peek p = do+ tb <- cIntConv `fmap` {#get CUdevprop.maxThreadsPerBlock#} p+ sm <- cIntConv `fmap` {#get CUdevprop.sharedMemPerBlock#} p+ cm <- cIntConv `fmap` {#get CUdevprop.totalConstantMemory#} p+ ws <- cIntConv `fmap` {#get CUdevprop.SIMDWidth#} p+ mp <- cIntConv `fmap` {#get CUdevprop.memPitch#} p+ rb <- cIntConv `fmap` {#get CUdevprop.regsPerBlock#} p+ cl <- cIntConv `fmap` {#get CUdevprop.clockRate#} p+ ta <- cIntConv `fmap` {#get CUdevprop.textureAlign#} p++ [t1,t2,t3] <- peekArrayWith cIntConv 3 =<< {#get CUdevprop.maxThreadsDim#} p+ [g1,g2,g3] <- peekArrayWith cIntConv 3 =<< {#get CUdevprop.maxGridSize#} p++ return CUDevProp+ {+ cuMaxThreadsPerBlock = tb,+ cuMaxBlockSize = (t1,t2,t3),+ cuMaxGridSize = (g1,g2,g3),+ cuSharedMemPerBlock = sm,+ cuTotalConstMem = cm,+ cuWarpSize = ws,+ cuMemPitch = mp,+ cuRegsPerBlock = rb,+ cuClockRate = cl,+ cuTextureAlignment = ta+ }+#endif+++-- |+-- Possible option flags for CUDA initialisation. Dummy instance until the API+-- exports actual option values.+--+data InitFlag+instance Enum InitFlag where+#ifdef USE_EMPTY_CASE+ toEnum x = case x of {}+ fromEnum x = case x of {}+#endif+++--------------------------------------------------------------------------------+-- Initialisation+--------------------------------------------------------------------------------++-- |+-- Initialise the CUDA driver API. This must be called before any other+-- driver function.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__INITIALIZE.html#group__CUDA__INITIALIZE_1g0a2f1517e1bd8502c7194c3a8c134bc3>+--+{-# INLINEABLE initialise #-}+initialise :: [InitFlag] -> IO ()+initialise !flags = nothingIfOk =<< cuInit flags <* enable_constructors++{-# INLINE enable_constructors #-}+{# fun unsafe enable_constructors { } -> `()' #}++{-# INLINE cuInit #-}+{# fun unsafe cuInit+ { combineBitMasks `[InitFlag]' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Device Management+--------------------------------------------------------------------------------++-- |+-- Return the compute compatibility revision supported by the device+--+{-# INLINEABLE capability #-}+capability :: Device -> IO Compute+#if CUDA_VERSION >= 5000+capability !dev =+ Compute <$> attribute dev ComputeCapabilityMajor+ <*> attribute dev ComputeCapabilityMinor+#else+-- Deprecated as of CUDA-5.0+--+capability !dev =+ (\(!s,!a,!b) -> resultIfOk (s,Compute a b)) =<< cuDeviceComputeCapability dev++{-# INLINE cuDeviceComputeCapability #-}+{# fun unsafe cuDeviceComputeCapability+ { alloca- `Int' peekIntConv*+ , alloca- `Int' peekIntConv*+ , useDevice `Device' } -> `Status' cToEnum #}+#endif+++-- |+-- Return a handle to the compute device at the given ordinal.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g8bdd1cc7201304b01357b8034f6587cb>+--+{-# INLINEABLE device #-}+device :: Int -> IO Device+device !d = resultIfOk =<< cuDeviceGet d++{-# INLINE cuDeviceGet #-}+{# fun unsafe cuDeviceGet+ { alloca- `Device' dev*+ , cIntConv `Int' } -> `Status' cToEnum #}+ where dev = liftM Device . peek+++-- |+-- Return the selected attribute for the given device.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g9c3e1414f0ad901d3278a4d6645fc266>+--+{-# INLINEABLE attribute #-}+attribute :: Device -> DeviceAttribute -> IO Int+attribute !d !a = resultIfOk =<< cuDeviceGetAttribute a d++{-# INLINE cuDeviceGetAttribute #-}+{# fun unsafe cuDeviceGetAttribute+ { alloca- `Int' peekIntConv*+ , cFromEnum `DeviceAttribute'+ , useDevice `Device' } -> `Status' cToEnum #}+++-- |+-- Return the number of device with compute capability > 1.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1g52b5ce05cb8c5fb6831b2c0ff2887c74>+--+{-# INLINEABLE count #-}+count :: IO Int+count = resultIfOk =<< cuDeviceGetCount++{-# INLINE cuDeviceGetCount #-}+{# fun unsafe cuDeviceGetCount+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+++-- |+-- The identifying name of the device.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1gef75aa30df95446a845f2a7b9fffbb7f>+--+{-# INLINEABLE name #-}+name :: Device -> IO String+name !d = resultIfOk =<< cuDeviceGetName d++{-# INLINE cuDeviceGetName #-}+{# fun unsafe cuDeviceGetName+ { allocaS- `String'& peekS*+ , useDevice `Device' } -> `Status' cToEnum #}+ where+ len = 512+ allocaS a = allocaBytes len $ \p -> a (p, cIntConv len)+ peekS s _ = peekCString s+++-- |+-- Return the properties of the selected device+--+{-# INLINEABLE props #-}+props :: Device -> IO DeviceProperties+props !d = do++#if CUDA_VERSION < 5000+ -- Old versions of the CUDA API used the separate cuDeviceGetProperties+ -- function to probe some properties, and cuDeviceGetAttribute for+ -- others. As of CUDA-5.0, the former was deprecated and its+ -- functionality subsumed by the latter, which we use below.+ --+ p <- resultIfOk =<< cuDeviceGetProperties d+ let cm = cuTotalConstMem p+ sm = cuSharedMemPerBlock p+ rb = cuRegsPerBlock p+ ws = cuWarpSize p+ tb = cuMaxThreadsPerBlock p+ bs = cuMaxBlockSize p+ gs = cuMaxGridSize p+ cl = cuClockRate p+ mp = cuMemPitch p+ ta = cuTextureAlignment p+#else+ cm <- fromIntegral <$> attribute d TotalConstantMemory+ sm <- fromIntegral <$> attribute d SharedMemoryPerBlock+ mp <- fromIntegral <$> attribute d MaxPitch+ ta <- fromIntegral <$> attribute d TextureAlignment+ cl <- attribute d ClockRate+ ws <- attribute d WarpSize+ rb <- attribute d RegistersPerBlock+ tb <- attribute d MaxThreadsPerBlock+ bs <- (,,) <$> attribute d MaxBlockDimX+ <*> attribute d MaxBlockDimY+ <*> attribute d MaxBlockDimZ+ gs <- (,,) <$> attribute d MaxGridDimX+ <*> attribute d MaxGridDimY+ <*> attribute d MaxGridDimZ+#endif++ -- The rest of the properties.+ --+ n <- name d+ cc <- capability d+ gm <- totalMem d+ pc <- attribute d MultiprocessorCount+ md <- toEnum `fmap` attribute d ComputeMode+ ov <- toBool `fmap` attribute d GpuOverlap+ ke <- toBool `fmap` attribute d KernelExecTimeout+ tg <- toBool `fmap` attribute d Integrated+ hm <- toBool `fmap` attribute d CanMapHostMemory+#if CUDA_VERSION >= 3000+ ck <- toBool `fmap` attribute d ConcurrentKernels+ ee <- toBool `fmap` attribute d EccEnabled+ u1 <- attribute d MaximumTexture1dWidth+ u21 <- attribute d MaximumTexture2dWidth+ u22 <- attribute d MaximumTexture2dHeight+ u31 <- attribute d MaximumTexture3dWidth+ u32 <- attribute d MaximumTexture3dHeight+ u33 <- attribute d MaximumTexture3dDepth+#endif+#if CUDA_VERSION >= 4000+ ae <- attribute d AsyncEngineCount+ l2 <- attribute d L2CacheSize+ tm <- attribute d MaxThreadsPerMultiprocessor+ mw <- attribute d GlobalMemoryBusWidth+ mc <- attribute d MemoryClockRate+ pb <- attribute d PciBusId+ pd <- attribute d PciDeviceId+ pm <- attribute d PciDomainId+ ua <- toBool `fmap` attribute d UnifiedAddressing+ tcc <- toBool `fmap` attribute d TccDriver+#endif+#if CUDA_VERSION >= 5050+ sp <- toBool `fmap` attribute d StreamPrioritiesSupported+#endif+#if CUDA_VERSION >= 6000+ gl1 <- toBool `fmap` attribute d GlobalL1CacheSupported+ ll1 <- toBool `fmap` attribute d LocalL1CacheSupported+ mm <- toBool `fmap` attribute d ManagedMemory+ mg <- toBool `fmap` attribute d MultiGpuBoard+ mid <- attribute d MultiGpuBoardGroupId+#endif++ return DeviceProperties+ {+ deviceName = n+ , computeCapability = cc+ , totalGlobalMem = gm+ , totalConstMem = cm+ , sharedMemPerBlock = sm+ , regsPerBlock = rb+ , warpSize = ws+ , maxThreadsPerBlock = tb+ , maxBlockSize = bs+ , maxGridSize = gs+ , clockRate = cl+ , multiProcessorCount = pc+ , memPitch = mp+ , textureAlignment = ta+ , computeMode = md+ , deviceOverlap = ov+ , kernelExecTimeoutEnabled = ke+ , integrated = tg+ , canMapHostMemory = hm+#if CUDA_VERSION >= 3000+ , concurrentKernels = ck+ , eccEnabled = ee+ , maxTextureDim1D = u1+ , maxTextureDim2D = (u21,u22)+ , maxTextureDim3D = (u31,u32,u33)+#endif+#if CUDA_VERSION >= 4000+ , asyncEngineCount = ae+ , cacheMemL2 = l2+ , maxThreadsPerMultiProcessor = tm+ , memBusWidth = mw+ , memClockRate = mc+ , pciInfo = PCI pb pd pm+ , tccDriverEnabled = tcc+ , unifiedAddressing = ua+#endif+#if CUDA_VERSION >= 5050+ , streamPriorities = sp+#endif+#if CUDA_VERSION >= 6000+ , globalL1Cache = gl1+ , localL1Cache = ll1+ , managedMemory = mm+ , multiGPUBoard = mg+ , multiGPUBoardGroupID = mid+#endif+ }++#if CUDA_VERSION < 5000+-- Deprecated as of CUDA-5.0+{-# INLINE cuDeviceGetProperties #-}+{# fun unsafe cuDeviceGetProperties+ { alloca- `CUDevProp' peek*+ , useDevice `Device' } -> `Status' cToEnum #}+#endif+++-- |+-- The total memory available on the device (bytes).+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__DEVICE.html#group__CUDA__DEVICE_1gc6a0d6551335a3780f9f3c967a0fde5d>+--+{-# INLINEABLE totalMem #-}+totalMem :: Device -> IO Int64+totalMem !d = resultIfOk =<< cuDeviceTotalMem d++{-# INLINE cuDeviceTotalMem #-}+{# fun unsafe cuDeviceTotalMem+ { alloca- `Int64' peekIntConv*+ , useDevice `Device' } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Driver/Error.chs view
@@ -0,0 +1,212 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Error+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Error handling+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Error (++ -- * CUDA Errors+ Status(..), CUDAException(..),+ describe,+ cudaError, cudaErrorIO, requireSDK,+ resultIfOk, nothingIfOk,++) where++-- Friends+import Foreign.CUDA.Internal.C2HS+import Text.Show.Describe++-- System+import Control.Exception+import Control.Monad+import Data.Typeable+import Foreign.C+import Foreign.Marshal+import Foreign.Ptr+import Foreign.Storable+import Language.Haskell.TH+import System.IO.Unsafe+import Text.Printf+++#include "cbits/stubs.h"+{# context lib="cuda" #}+++--------------------------------------------------------------------------------+-- Return Status+--------------------------------------------------------------------------------++--+-- Error Codes+--+{# enum CUresult as Status+ { underscoreToCase+ , CUDA_SUCCESS as Success+ , CUDA_ERROR_NO_BINARY_FOR_GPU as NoBinaryForGPU+ , CUDA_ERROR_INVALID_PTX as InvalidPTX+ , CUDA_ERROR_INVALID_PC as InvalidPC+ }+ with prefix="CUDA_ERROR" deriving (Eq, Show) #}+++-- |+-- Return a descriptive error string associated with a particular error code+--+instance Describe Status where+#if CUDA_VERSION >= 6000+ describe status =+ case cuGetErrorString status of+ (Success, msg) -> msg+ (err, _) -> throw (ExitCode err)++{# fun pure unsafe cuGetErrorString+ { cFromEnum `Status'+ , alloca- `String' ppeek* } -> `Status' cToEnum #}+ where+ ppeek = peek >=> peekCString+#else+ describe Success = "no error"+ describe InvalidValue = "invalid argument"+ describe OutOfMemory = "out of memory"+ describe NotInitialized = "driver not initialised"+ describe Deinitialized = "driver deinitialised"+ describe NoDevice = "no CUDA-capable device is available"+ describe InvalidDevice = "invalid device ordinal"+ describe InvalidImage = "invalid kernel image"+ describe InvalidContext = "invalid context handle"+ describe ContextAlreadyCurrent = "context already current"+ describe MapFailed = "map failed"+ describe UnmapFailed = "unmap failed"+ describe ArrayIsMapped = "array is mapped"+ describe AlreadyMapped = "already mapped"+ describe NoBinaryForGPU = "no binary available for this GPU"+ describe AlreadyAcquired = "resource already acquired"+ describe NotMapped = "not mapped"+ describe InvalidSource = "invalid source"+ describe FileNotFound = "file not found"+ describe InvalidHandle = "invalid handle"+ describe NotFound = "not found"+ describe NotReady = "device not ready"+ describe LaunchFailed = "unspecified launch failure"+ describe LaunchOutOfResources = "too many resources requested for launch"+ describe LaunchTimeout = "the launch timed out and was terminated"+ describe LaunchIncompatibleTexturing = "launch with incompatible texturing"+#if CUDA_VERSION >= 3000+ describe NotMappedAsArray = "mapped resource not available for access as an array"+ describe NotMappedAsPointer = "mapped resource not available for access as a pointer"+ describe EccUncorrectable = "uncorrectable ECC error detected"+#endif+#if CUDA_VERSION >= 3000 && CUDA_VERSION < 3020+ describe PointerIs64bit = "attempt to retrieve a 64-bit pointer via a 32-bit API function"+ describe SizeIs64bit = "attempt to retrieve 64-bit size via a 32-bit API function"+#endif+#if CUDA_VERSION >= 3010+ describe UnsupportedLimit = "limits not supported by device"+ describe SharedObjectSymbolNotFound = "link to a shared object failed to resolve"+ describe SharedObjectInitFailed = "shared object initialisation failed"+#endif+#if CUDA_VERSION >= 3020+ describe OperatingSystem = "operating system call failed"+#endif+#if CUDA_VERSION >= 4000+ describe ProfilerDisabled = "profiling APIs disabled: application running with visual profiler"+ describe ProfilerNotInitialized = "profiler not initialised"+ describe ProfilerAlreadyStarted = "profiler already started"+ describe ProfilerAlreadyStopped = "profiler already stopped"+ describe ContextAlreadyInUse = "context is already bound to a thread and in use"+ describe PeerAccessAlreadyEnabled = "peer access already enabled"+ describe PeerAccessNotEnabled = "peer access has not been enabled"+ describe PrimaryContextActive = "primary context for this device has already been initialised"+ describe ContextIsDestroyed = "context already destroyed"+#endif+#if CUDA_VERSION >= 4010+ describe Assert = "device-side assert triggered"+ describe TooManyPeers = "peer mapping resources exhausted"+ describe HostMemoryAlreadyRegistered = "part or all of the requested memory range is already mapped"+ describe HostMemoryNotRegistered = "pointer does not correspond to a registered memory region"+#endif+#if CUDA_VERSION >= 5000+ describe PeerAccessUnsupported = "peer access is not supported across the given devices"+ describe NotPermitted = "not permitted"+ describe NotSupported = "not supported"+#endif+ describe Unknown = "unknown error"+#endif+++--------------------------------------------------------------------------------+-- Exceptions+--------------------------------------------------------------------------------++data CUDAException+ = ExitCode Status+ | UserError String+ deriving Typeable++instance Exception CUDAException++instance Show CUDAException where+ showsPrec _ (ExitCode s) = showString ("CUDA Exception: " ++ describe s)+ showsPrec _ (UserError s) = showString ("CUDA Exception: " ++ s)+++-- |+-- Raise a CUDAException. Exceptions can be thrown from pure code, but can only+-- be caught in the 'IO' monad.+--+{-# RULES "cudaError/IO" cudaError = cudaErrorIO #-}+{-# NOINLINE [1] cudaError #-}+cudaError :: String -> a+cudaError s = throw (UserError s)++-- |+-- Raise a CUDAException in the IO Monad+--+cudaErrorIO :: String -> IO a+cudaErrorIO s = throwIO (UserError s)++-- |+-- A specially formatted error message+--+requireSDK :: Name -> Double -> a+requireSDK n v = cudaError $ printf "'%s' requires at least cuda-%3.1f\n" (show n) v+++--------------------------------------------------------------------------------+-- Helper Functions+--------------------------------------------------------------------------------+++-- |+-- Return the results of a function on successful execution, otherwise throw an+-- exception with an error string associated with the return code+--+{-# INLINE resultIfOk #-}+resultIfOk :: (Status, a) -> IO a+resultIfOk (status, !result) =+ case status of+ Success -> return result+ _ -> throwIO (ExitCode status)+++-- |+-- Throw an exception with an error string associated with an unsuccessful+-- return code, otherwise return unit.+--+{-# INLINE nothingIfOk #-}+nothingIfOk :: Status -> IO ()+nothingIfOk status =+ case status of+ Success -> return ()+ _ -> throwIO (ExitCode status)+
+ src/Foreign/CUDA/Driver/Event.chs view
@@ -0,0 +1,163 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Event+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Event management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Event (++ -- * Event Management+ Event(..), EventFlag(..), WaitFlag,+ create, destroy, elapsedTime, query, record, wait, block++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Types+import Foreign.CUDA.Internal.C2HS+import Foreign.CUDA.Driver.Error++-- System+import Foreign+import Foreign.C+import Data.Maybe+import Control.Monad ( liftM )+import Control.Exception ( throwIO )+++--------------------------------------------------------------------------------+-- Event management+--------------------------------------------------------------------------------++-- |+-- Create a new event+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g450687e75f3ff992fe01662a43d9d3db>+--+{-# INLINEABLE create #-}+create :: [EventFlag] -> IO Event+create !flags = resultIfOk =<< cuEventCreate flags++{-# INLINE cuEventCreate #-}+{# fun unsafe cuEventCreate+ { alloca- `Event' peekEvt*+ , combineBitMasks `[EventFlag]' } -> `Status' cToEnum #}+ where peekEvt = liftM Event . peek+++-- |+-- Destroy an event+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g593ec73a8ec5a5fc031311d3e4dca1ef>+--+{-# INLINEABLE destroy #-}+destroy :: Event -> IO ()+destroy !ev = nothingIfOk =<< cuEventDestroy ev++{-# INLINE cuEventDestroy #-}+{# fun unsafe cuEventDestroy+ { useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Determine the elapsed time (in milliseconds) between two events+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1gdfb1178807353bbcaa9e245da497cf97>+--+{-# INLINEABLE elapsedTime #-}+elapsedTime :: Event -> Event -> IO Float+elapsedTime !ev1 !ev2 = resultIfOk =<< cuEventElapsedTime ev1 ev2++{-# INLINE cuEventElapsedTime #-}+{# fun unsafe cuEventElapsedTime+ { alloca- `Float' peekFloatConv*+ , useEvent `Event'+ , useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Determines if a event has actually been recorded+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g6f0704d755066b0ee705749ae911deef>+--+{-# INLINEABLE query #-}+query :: Event -> IO Bool+query !ev =+ cuEventQuery ev >>= \rv ->+ case rv of+ Success -> return True+ NotReady -> return False+ _ -> throwIO (ExitCode rv)++{-# INLINE cuEventQuery #-}+{# fun unsafe cuEventQuery+ { useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Record an event once all operations in the current context (or optionally+-- specified stream) have completed. This operation is asynchronous.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g95424d3be52c4eb95d83861b70fb89d1>+--+{-# INLINEABLE record #-}+record :: Event -> Maybe Stream -> IO ()+record !ev !mst =+ nothingIfOk =<< cuEventRecord ev (fromMaybe defaultStream mst)++{-# INLINE cuEventRecord #-}+{# fun unsafe cuEventRecord+ { useEvent `Event'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Makes all future work submitted to the (optional) stream wait until the given+-- event reports completion before beginning execution. Synchronisation is+-- performed on the device, including when the event and stream are from+-- different device contexts.+--+-- Requires CUDA-3.2.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g6a898b652dfc6aa1d5c8d97062618b2f>+--+{-# INLINEABLE wait #-}+wait :: Event -> Maybe Stream -> [WaitFlag] -> IO ()+#if CUDA_VERSION < 3020+wait _ _ _ = requireSDK 'wait 3.2+#else+wait !ev !mst !flags =+ nothingIfOk =<< cuStreamWaitEvent (fromMaybe defaultStream mst) ev flags++{-# INLINE cuStreamWaitEvent #-}+{# fun unsafe cuStreamWaitEvent+ { useStream `Stream'+ , useEvent `Event'+ , combineBitMasks `[WaitFlag]' } -> `Status' cToEnum #}+#endif++-- |+-- Wait until the event has been recorded+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EVENT.html#group__CUDA__EVENT_1g9e520d34e51af7f5375610bca4add99c>+--+{-# INLINEABLE block #-}+block :: Event -> IO ()+block !ev = nothingIfOk =<< cuEventSynchronize ev++{-# INLINE cuEventSynchronize #-}+{# fun cuEventSynchronize+ { useEvent `Event' } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Driver/Exec.chs view
@@ -0,0 +1,380 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Exec+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Kernel execution control for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Exec (++ -- * Kernel Execution+ Fun(Fun), FunParam(..), FunAttribute(..), SharedMem(..),+ requires,+ setCacheConfigFun,+ setSharedMemConfigFun,+ launchKernel, launchKernel',++ -- Deprecated since CUDA-4.0+ setBlockShape, setSharedSize, setParams, launch,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Internal.C2HS+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Context ( Cache(..), SharedMem(..) )+import Foreign.CUDA.Driver.Stream ( Stream(..), defaultStream )++-- System+import Foreign+import Foreign.C+import Data.Maybe+import Control.Monad ( zipWithM_ )+++#if CUDA_VERSION >= 4000+{-# DEPRECATED setBlockShape, setSharedSize, setParams, launch+ "use launchKernel instead" #-}+#endif+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A @\_\_global\_\_@ device function+--+newtype Fun = Fun { useFun :: {# type CUfunction #}}+++-- |+-- Function attributes+--+{# enum CUfunction_attribute as FunAttribute+ { underscoreToCase+ , MAX_THREADS_PER_BLOCK as MaxKernelThreadsPerBlock+ , MAX as CU_FUNC_ATTRIBUTE_MAX } -- ignore+ with prefix="CU_FUNC_ATTRIBUTE" deriving (Eq, Show) #}++-- |+-- Kernel function parameters+--+data FunParam where+ IArg :: !Int32 -> FunParam+ FArg :: !Float -> FunParam+ VArg :: Storable a => !a -> FunParam++instance Storable FunParam where+ sizeOf (IArg _) = sizeOf (undefined :: CUInt)+ sizeOf (FArg _) = sizeOf (undefined :: CFloat)+ sizeOf (VArg v) = sizeOf v++ alignment (IArg _) = alignment (undefined :: CUInt)+ alignment (FArg _) = alignment (undefined :: CFloat)+ alignment (VArg v) = alignment v++ poke p (IArg i) = poke (castPtr p) i+ poke p (FArg f) = poke (castPtr p) f+ poke p (VArg v) = poke (castPtr p) v++ peek _ = error "Can not peek Foreign.CUDA.Driver.FunParam"+++--------------------------------------------------------------------------------+-- Execution Control+--------------------------------------------------------------------------------++-- |+-- Returns the value of the selected attribute requirement for the given kernel.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g5e92a1b0d8d1b82cb00dcfb2de15961b>+--+{-# INLINEABLE requires #-}+requires :: Fun -> FunAttribute -> IO Int+requires !fn !att = resultIfOk =<< cuFuncGetAttribute att fn++{-# INLINE cuFuncGetAttribute #-}+{# fun unsafe cuFuncGetAttribute+ { alloca- `Int' peekIntConv*+ , cFromEnum `FunAttribute'+ , useFun `Fun' } -> `Status' cToEnum #}+++-- |+-- On devices where the L1 cache and shared memory use the same hardware+-- resources, this sets the preferred cache configuration for the given device+-- function. This is only a preference; the driver is free to choose a different+-- configuration as required to execute the function.+--+-- Switching between configuration modes may insert a device-side+-- synchronisation point for streamed kernel launches.+--+-- Requires CUDA-3.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g40f8c11e81def95dc0072a375f965681>+--+{-# INLINEABLE setCacheConfigFun #-}+setCacheConfigFun :: Fun -> Cache -> IO ()+#if CUDA_VERSION < 3000+setCacheConfigFun _ _ = requireSDK 'setCacheConfigFun 3.0+#else+setCacheConfigFun !fn !pref = nothingIfOk =<< cuFuncSetCacheConfig fn pref++{-# INLINE cuFuncSetCacheConfig #-}+{# fun unsafe cuFuncSetCacheConfig+ { useFun `Fun'+ , cFromEnum `Cache' } -> `Status' cToEnum #}+#endif+++-- |+-- Set the shared memory configuration of a device function.+--+-- On devices with configurable shared memory banks, this will force all+-- subsequent launches of the given device function to use the specified+-- shared memory bank size configuration. On launch of the function, the+-- shared memory configuration of the device will be temporarily changed if+-- needed to suit the function configuration. Changes in shared memory+-- configuration may introduction a device side synchronisation between+-- kernel launches.+--+-- Any per-function configuration specified by 'setSharedMemConfig' will+-- override the context-wide configuration set with+-- 'Foreign.CUDA.Driver.Context.Config.setSharedMem'.+--+-- Changing the shared memory bank size will not increase shared memory+-- usage or affect occupancy of kernels, but may have major effects on+-- performance. Larger bank sizes will allow for greater potential+-- bandwidth to shared memory, but will change what kinds of accesses to+-- shared memory will result in bank conflicts.+--+-- This function will do nothing on devices with fixed shared memory bank+-- size.+--+-- Requires CUDA-5.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1g430b913f24970e63869635395df6d9f5>+--+{-# INLINEABLE setSharedMemConfigFun #-}+setSharedMemConfigFun :: Fun -> SharedMem -> IO ()+#if CUDA_VERSION < 5000+setSharedMemConfigFun _ _ = requireSDK 'setSharedMemConfigFun 5.0+#else+setSharedMemConfigFun !fun !pref = nothingIfOk =<< cuFuncSetSharedMemConfig fun pref++{-# INLINE cuFuncSetSharedMemConfig #-}+{# fun unsafe cuFuncSetSharedMemConfig+ { useFun `Fun'+ , cFromEnum `SharedMem'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Invoke a kernel on a @(gx * gy * gz)@ grid of blocks, where each block+-- contains @(tx * ty * tz)@ threads and has access to a given number of bytes+-- of shared memory. The launch may also be associated with a specific 'Stream'.+--+-- In 'launchKernel', the number of kernel parameters and their offsets and+-- sizes do not need to be specified, as this information is retrieved directly+-- from the kernel's image. This requires the kernel to have been compiled with+-- toolchain version 3.2 or later.+--+-- The alternative 'launchKernel'' will pass the arguments in directly,+-- requiring the application to know the size and alignment/padding of each+-- kernel parameter.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1gb8f3dc3031b40da29d5f9a7139e52e15>+--+{-# INLINEABLE launchKernel #-}+{-# INLINEABLE launchKernel' #-}+launchKernel, launchKernel'+ :: Fun -- ^ function to execute+ -> (Int,Int,Int) -- ^ block grid dimension+ -> (Int,Int,Int) -- ^ thread block shape+ -> Int -- ^ shared memory (bytes)+ -> Maybe Stream -- ^ (optional) stream to execute in+ -> [FunParam] -- ^ list of function parameters+ -> IO ()+#if CUDA_VERSION >= 4000+launchKernel !fn (!gx,!gy,!gz) (!tx,!ty,!tz) !sm !mst !args+ = (=<<) nothingIfOk+ $ withMany withFP args+ $ \pa -> withArray pa+ $ \pp -> cuLaunchKernel fn gx gy gz tx ty tz sm st pp nullPtr+ where+ !st = fromMaybe defaultStream mst++ withFP :: FunParam -> (Ptr FunParam -> IO b) -> IO b+ withFP !p !f = case p of+ IArg v -> with' v (f . castPtr)+ FArg v -> with' v (f . castPtr)+ VArg v -> with' v (f . castPtr)++ -- can't use the standard 'with' because 'alloca' will pass an undefined+ -- dummy argument when determining 'sizeOf' and 'alignment', but sometimes+ -- instances in Accelerate need to evaluate this argument.+ --+ with' :: Storable a => a -> (Ptr a -> IO b) -> IO b+ with' !val !f =+ allocaBytes (sizeOf val) $ \ptr -> do+ poke ptr val+ f ptr+++launchKernel' !fn (!gx,!gy,!gz) (!tx,!ty,!tz) !sm !mst !args+ = (=<<) nothingIfOk+ $ with bytes+ $ \pb -> withArray' args+ $ \pa -> withArray0 nullPtr [buffer, castPtr pa, size, castPtr pb]+ $ \pp -> cuLaunchKernel fn gx gy gz tx ty tz sm st nullPtr pp+ where+ buffer = wordPtrToPtr 0x01 -- CU_LAUNCH_PARAM_BUFFER_POINTER+ size = wordPtrToPtr 0x02 -- CU_LAUNCH_PARAM_BUFFER_SIZE+ bytes = foldl (\a x -> a + sizeOf x) 0 args+ st = fromMaybe defaultStream mst++ -- can't use the standard 'withArray' because 'mallocArray' will pass+ -- 'undefined' to 'sizeOf' when determining how many bytes to allocate, but+ -- our Storable instance for FunParam needs to dispatch on each constructor,+ -- hence evaluating the undefined.+ --+ withArray' !vals !f =+ allocaBytes bytes $ \ptr -> do+ pokeArray ptr vals+ f ptr+++{-# INLINE cuLaunchKernel #-}+{# fun unsafe cuLaunchKernel+ { useFun `Fun'+ , `Int', `Int', `Int'+ , `Int', `Int', `Int'+ , `Int'+ , useStream `Stream'+ , castPtr `Ptr (Ptr FunParam)'+ , castPtr `Ptr (Ptr ())' } -> `Status' cToEnum #}++#else+launchKernel !fn (!gx,!gy,_) (!tx,!ty,!tz) !sm !mst !args = do+ setParams fn args+ setSharedSize fn (toInteger sm)+ setBlockShape fn (tx,ty,tz)+ launch fn (gx,gy) mst++launchKernel' = launchKernel+#endif+++--------------------------------------------------------------------------------+-- Deprecated+--------------------------------------------------------------------------------++-- |+-- Invoke the kernel on a size @(w,h)@ grid of blocks. Each block contains the+-- number of threads specified by a previous call to 'setBlockShape'. The launch+-- may also be associated with a specific 'Stream'.+--+{-# INLINEABLE launch #-}+launch :: Fun -> (Int,Int) -> Maybe Stream -> IO ()+launch !fn (!w,!h) mst =+ nothingIfOk =<< cuLaunchGridAsync fn w h (fromMaybe defaultStream mst)++{-# INLINE cuLaunchGridAsync #-}+{# fun unsafe cuLaunchGridAsync+ { useFun `Fun'+ , `Int'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Specify the @(x,y,z)@ dimensions of the thread blocks that are created when+-- the given kernel function is launched.+--+{-# INLINEABLE setBlockShape #-}+setBlockShape :: Fun -> (Int,Int,Int) -> IO ()+setBlockShape !fn (!x,!y,!z) = nothingIfOk =<< cuFuncSetBlockShape fn x y z++{-# INLINE cuFuncSetBlockShape #-}+{# fun unsafe cuFuncSetBlockShape+ { useFun `Fun'+ , `Int'+ , `Int'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Set the number of bytes of dynamic shared memory to be available to each+-- thread block when the function is launched+--+{-# INLINEABLE setSharedSize #-}+setSharedSize :: Fun -> Integer -> IO ()+setSharedSize !fn !bytes = nothingIfOk =<< cuFuncSetSharedSize fn bytes++{-# INLINE cuFuncSetSharedSize #-}+{# fun unsafe cuFuncSetSharedSize+ { useFun `Fun'+ , cIntConv `Integer' } -> `Status' cToEnum #}+++-- |+-- Set the parameters that will specified next time the kernel is invoked+--+{-# INLINEABLE setParams #-}+setParams :: Fun -> [FunParam] -> IO ()+setParams !fn !prs = do+ zipWithM_ (set fn) offsets prs+ nothingIfOk =<< cuParamSetSize fn (last offsets)+ where+ offsets = scanl (\a b -> a + size b) 0 prs++ size (IArg _) = sizeOf (undefined :: CUInt)+ size (FArg _) = sizeOf (undefined :: CFloat)+ size (VArg v) = sizeOf v++ set f o (IArg v) = nothingIfOk =<< cuParamSeti f o v+ set f o (FArg v) = nothingIfOk =<< cuParamSetf f o v+ set f o (VArg v) = with v $ \p -> (nothingIfOk =<< cuParamSetv f o p (sizeOf v))+++{-# INLINE cuParamSetSize #-}+{# fun unsafe cuParamSetSize+ { useFun `Fun'+ , `Int' } -> `Status' cToEnum #}++{-# INLINE cuParamSeti #-}+{# fun unsafe cuParamSeti+ { useFun `Fun'+ , `Int'+ , `Int32' } -> `Status' cToEnum #}++{-# INLINE cuParamSetf #-}+{# fun unsafe cuParamSetf+ { useFun `Fun'+ , `Int'+ , `Float' } -> `Status' cToEnum #}++{-# INLINE cuParamSetv #-}+{# fun unsafe cuParamSetv+ `Storable a' =>+ { useFun `Fun'+ , `Int'+ , castPtr `Ptr a'+ , `Int' } -> `Status' cToEnum #}++
+ src/Foreign/CUDA/Driver/IPC/Event.chs view
@@ -0,0 +1,140 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.IPC.Event+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- IPC event management for low-level driver interface.+--+-- Restricted to devices which support unified addressing on Linux+-- operating systems.+--+-- Since CUDA-4.1.+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.IPC.Event (++ IPCEvent,+ export, open,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Event+import Foreign.CUDA.Internal.C2HS++-- System+import Control.Monad+import Prelude++import Foreign.C+import Foreign.Ptr+import Foreign.ForeignPtr+import Foreign.Marshal+import Foreign.Storable+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A CUDA inter-process event handle.+--+newtype IPCEvent = IPCEvent { useIPCEvent :: IPCEventHandle }+ deriving (Eq, Show)+++--------------------------------------------------------------------------------+-- IPC event management+--------------------------------------------------------------------------------++-- |+-- Create an inter-process event handle for a previously allocated event.+-- The event must be created with the 'Interprocess' and 'DisableTiming'+-- event flags. The returned handle may then be sent to another process and+-- 'open'ed to allow efficient hardware synchronisation between GPU work in+-- other processes.+--+-- After the event has been opened in the importing process, 'record',+-- 'block', 'wait', 'query' may be used in either process.+--+-- Performing operations on the imported event after the event has been+-- 'destroy'ed in the exporting process is undefined.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gea02eadd12483de5305878b13288a86c>+--+{-# INLINEABLE export #-}+export :: Event -> IO IPCEvent+#if CUDA_VERSION < 4010+export _ = requireSDK 'create 4.1+#else+export !ev = do+ h <- newIPCEventHandle+ r <- cuIpcGetEventHandle h ev+ resultIfOk (r, IPCEvent h)++{-# INLINE cuIpcGetEventHandle #-}+{# fun unsafe cuIpcGetEventHandle+ { withForeignPtr* `IPCEventHandle'+ , useEvent `Event'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Open an inter-process event handle for use in the current process,+-- returning an event that can be used in the current process and behaving+-- as a locally created event with the 'DisableTiming' flag specified.+--+-- The event must be freed with 'destroy'. Performing operations on the+-- imported event after the exported event has been 'destroy'ed in the+-- exporting process is undefined.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf1d525918b6c643b99ca8c8e42e36c2e>+--+{-# INLINEABLE open #-}+open :: IPCEvent -> IO Event+#if CUDA_VERSION < 4010+open _ = requireSDK 'open 4.1+#else+open !ev = resultIfOk =<< cuIpcOpenEventHandle (useIPCEvent ev)++{-# INLINE cuIpcOpenEventHandle #-}+{# fun unsafe cuIpcOpenEventHandle+ { alloca- `Event' peekEvent*+ , withForeignPtr* `IPCEventHandle'+ }+ -> `Status' cToEnum #}+ where+ peekEvent = liftM Event . peek+#endif+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++type IPCEventHandle = ForeignPtr ()++newIPCEventHandle :: IO IPCEventHandle+#if CUDA_VERSION < 4010+newIPCEventHandle = requireSDK 'newIPCEventHandle 4.1+#else+newIPCEventHandle = mallocForeignPtrBytes {#sizeof CUipcEventHandle#}+#endif+
+ src/Foreign/CUDA/Driver/IPC/Marshal.chs view
@@ -0,0 +1,177 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.IPC.Marshal+-- Copyright : [2009..2015] Trevor L. McDonell+-- License : BSD+--+-- IPC memory management for low-level driver interface.+--+-- Restricted to devices which support unified addressing on Linux+-- operating systems.+--+-- Since CUDA-4.0.+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.IPC.Marshal (++ -- ** IPC memory management+ IPCDevicePtr, IPCFlag(..),+ export, open, close,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Ptr+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS+import Foreign.CUDA.Driver.Marshal++-- System+import Control.Monad+import Prelude++import Foreign.C+import Foreign.Ptr+import Foreign.ForeignPtr+import Foreign.Marshal+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A CUDA memory handle used for inter-process communication.+--+newtype IPCDevicePtr a = IPCDevicePtr { useIPCDevicePtr :: IPCMemHandle }+ deriving (Eq, Show)+++-- |+-- Flags for controlling IPC memory access+--+#if CUDA_VERSION < 4010+data IPCFlag+#else+{# enum CUipcMem_flags as IPCFlag+ { underscoreToCase }+ with prefix="CU_IPC_MEM" deriving (Eq, Show, Bounded) #}+#endif+++--------------------------------------------------------------------------------+-- IPC memory management+--------------------------------------------------------------------------------++-- |+-- Create an inter-process memory handle for an existing device memory+-- allocation. The handle can then be sent to another process and made+-- available to that process via 'open'.+--+-- Requires CUDA-4.1.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g6f1b5be767b275f016523b2ac49ebec1>+--+{-# INLINEABLE export #-}+export :: DevicePtr a -> IO (IPCDevicePtr a)+#if CUDA_VERSION < 4010+export _ = requireSDK 'export 4.1+#else+export !dptr = do+ h <- newIPCMemHandle+ r <- cuIpcGetMemHandle h dptr+ resultIfOk (r, IPCDevicePtr h)++{-# INLINE cuIpcGetMemHandle #-}+{# fun unsafe cuIpcGetMemHandle+ { withForeignPtr* `IPCMemHandle'+ , useDeviceHandle `DevicePtr a'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Open an inter-process memory handle exported from another process,+-- returning a device pointer usable in the current process.+--+-- Maps memory exported by another process with 'create' into the current+-- device address space. For contexts on different devices, 'open' can+-- attempt to enable peer access if the user called+-- 'Foreign.CUDA.Driver.Context.Peer.add', and is controlled by the+-- 'LazyEnablePeerAccess' flag.+--+-- Each handle from a given device and context may only be 'open'ed by one+-- context per device per other process. Memory returned by 'open' must be+-- freed via 'close'.+--+-- Requires CUDA-4.1.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1ga8bd126fcff919a0c996b7640f197b79>+--+{-# INLINEABLE open #-}+open :: IPCDevicePtr a -> [IPCFlag]-> IO (DevicePtr a)+#if CUDA_VERSION < 4010+open _ _ = requireSDK 'open 4.1+#else+open !hdl !flags = resultIfOk =<< cuIpcOpenMemHandle (useIPCDevicePtr hdl) flags++{-# INLINE cuIpcOpenMemHandle #-}+{# fun unsafe cuIpcOpenMemHandle+ { alloca- `DevicePtr a' peekDeviceHandle*+ , withForeignPtr* `IPCMemHandle'+ , combineBitMasks `[IPCFlag]'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Close and unmap memory returned by 'open'. The original allocation in+-- the exporting process as well as imported mappings in other processes+-- are unaffected.+--+-- Any resources used to enable peer access will be freed if this is the+-- last mapping using them.+--+-- Requires CUDA-4.1.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gd6f5d5bcf6376c6853b64635b0157b9e>+--+{-# INLINEABLE close #-}+close :: DevicePtr a -> IO ()+#if CUDA_VERSION < 4010+close _ = requireSDK 'close 4.1+#else+close !dptr = nothingIfOk =<< cuIpcCloseMemHandle dptr++{-# INLINE cuIpcCloseMemHandle #-}+{# fun unsafe cuIpcCloseMemHandle+ { useDeviceHandle `DevicePtr a'+ }+ -> `Status' cToEnum #}+#endif+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++type IPCMemHandle = ForeignPtr ()++newIPCMemHandle :: IO IPCMemHandle+#if CUDA_VERSION < 4010+newIPCMemHandle = requireSDK 'newIPCMemHandle 4.1+#else+newIPCMemHandle = mallocForeignPtrBytes {#sizeof CUipcMemHandle#}+#endif+
+ src/Foreign/CUDA/Driver/Marshal.chs view
@@ -0,0 +1,1117 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_HADDOCK prune #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Marshal+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Memory management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Marshal (++ -- * Host Allocation+ AllocFlag(..),+ mallocHostArray, mallocHostForeignPtr, freeHost,+ registerArray, unregisterArray,++ -- * Device Allocation+ mallocArray, allocaArray, free,++ -- * Unified Memory Allocation+ AttachFlag(..),+ mallocManagedArray,++ -- * Marshalling+ peekArray, peekArrayAsync, peekArray2D, peekArray2DAsync, peekListArray,+ pokeArray, pokeArrayAsync, pokeArray2D, pokeArray2DAsync, pokeListArray,+ copyArray, copyArrayAsync, copyArray2D, copyArray2DAsync,+ copyArrayPeer, copyArrayPeerAsync,++ -- * Combined Allocation and Marshalling+ newListArray, newListArrayLen,+ withListArray, withListArrayLen,++ -- * Utility+ memset, memsetAsync,+ getDevicePtr, getBasePtr, getMemInfo,++ -- Internal+ useDeviceHandle, peekDeviceHandle++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Ptr+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Stream ( Stream(..), defaultStream )+import Foreign.CUDA.Driver.Context.Base ( Context(..) )+import Foreign.CUDA.Internal.C2HS++-- System+import Data.Int+import Data.Maybe+import Data.Word+import Unsafe.Coerce+import Control.Applicative+import Control.Exception+import Prelude++import Foreign.C+import Foreign.Ptr+import Foreign.ForeignPtr+import Foreign.Storable+import qualified Foreign.Marshal as F++#c+typedef enum CUmemhostalloc_option_enum {+ CU_MEMHOSTALLOC_OPTION_PORTABLE = CU_MEMHOSTALLOC_PORTABLE,+ CU_MEMHOSTALLOC_OPTION_DEVICE_MAPPED = CU_MEMHOSTALLOC_DEVICEMAP,+ CU_MEMHOSTALLOC_OPTION_WRITE_COMBINED = CU_MEMHOSTALLOC_WRITECOMBINED+} CUmemhostalloc_option;+#endc+++--------------------------------------------------------------------------------+-- Host Allocation+--------------------------------------------------------------------------------++-- |+-- Options for host allocation+--+{# enum CUmemhostalloc_option as AllocFlag+ { underscoreToCase }+ with prefix="CU_MEMHOSTALLOC_OPTION" deriving (Eq, Show, Bounded) #}++-- |+-- Allocate a section of linear memory on the host which is page-locked and+-- directly accessible from the device. The storage is sufficient to hold the+-- given number of elements of a storable type.+--+-- Note that since the amount of pageable memory is thusly reduced, overall+-- system performance may suffer. This is best used sparingly to allocate+-- staging areas for data exchange.+--+-- Host memory allocated in this way is automatically and immediately+-- accessible to all contexts on all devices which support unified+-- addressing.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gdd8311286d2c2691605362c689bc64e0>+--+{-# INLINEABLE mallocHostArray #-}+mallocHostArray :: Storable a => [AllocFlag] -> Int -> IO (HostPtr a)+mallocHostArray !flags = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (HostPtr a')+ doMalloc x !n = resultIfOk =<< cuMemHostAlloc (n * sizeOf x) flags++-- |+-- As 'mallocHostArray', but return a 'ForeignPtr' instead. The array will be+-- deallocated automatically once the last reference to the 'ForeignPtr' is+-- dropped.+--+{-# INLINEABLE mallocHostForeignPtr #-}+{-# SPECIALISE mallocHostForeignPtr :: [AllocFlag] -> Int -> IO (ForeignPtr Word8) #-}+mallocHostForeignPtr :: Storable a => [AllocFlag] -> Int -> IO (ForeignPtr a)+mallocHostForeignPtr !flags !size = do+ HostPtr ptr <- mallocHostArray flags size+ newForeignPtr finalizerMemFreeHost ptr++{-# INLINE cuMemHostAlloc #-}+{# fun unsafe cuMemHostAlloc+ { alloca'- `HostPtr a' peekHP*+ , `Int'+ , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}+ where+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+ peekHP !p = HostPtr . castPtr <$> peek p++-- Pointer to the foreign function to release host arrays, which may be used as+-- a finalizer. Technically this function has a non-void return type, but I am+-- hoping that that doesn't matter...+--+foreign import ccall "&cuMemFreeHost" finalizerMemFreeHost :: FinalizerPtr a++-- |+-- Free a section of page-locked host memory.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g62e0fdbe181dab6b1c90fa1a51c7b92c>+--+{-# INLINEABLE freeHost #-}+freeHost :: HostPtr a -> IO ()+freeHost !p = nothingIfOk =<< cuMemFreeHost p++{-# INLINE cuMemFreeHost #-}+{# fun unsafe cuMemFreeHost+ { useHP `HostPtr a' } -> `Status' cToEnum #}+ where+ useHP = castPtr . useHostPtr+++-- |+-- Page-locks the specified array (on the host) and maps it for the device(s) as+-- specified by the given allocation flags. Subsequently, the memory is accessed+-- directly by the device so can be read and written with much higher bandwidth+-- than pageable memory that has not been registered. The memory range is added+-- to the same tracking mechanism as 'mallocHostArray' to automatically+-- accelerate calls to functions such as 'pokeArray'.+--+-- Note that page-locking excessive amounts of memory may degrade system+-- performance, since it reduces the amount of pageable memory available. This+-- is best used sparingly to allocate staging areas for data exchange.+--+-- This function has limited support on Mac OS X. OS 10.7 or later is+-- required.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf0a9fe11544326dabd743b7aa6b54223>+--+{-# INLINEABLE registerArray #-}+registerArray :: Storable a => [AllocFlag] -> Int -> Ptr a -> IO (HostPtr a)+#if CUDA_VERSION < 4000+registerArray _ _ _ = requireSDK 'registerArray 4.0+#else+registerArray !flags !n = go undefined+ where+ go :: Storable b => b -> Ptr b -> IO (HostPtr b)+ go x !p = do+ status <- cuMemHostRegister p (n * sizeOf x) flags+ resultIfOk (status,HostPtr p)++{-# INLINE cuMemHostRegister #-}+{# fun unsafe cuMemHostRegister+ { castPtr `Ptr a'+ , `Int'+ , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}+#endif+++-- |+-- Unmaps the memory from the given pointer, and makes it pageable again.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g63f450c8125359be87b7623b1c0b2a14>+--+{-# INLINEABLE unregisterArray #-}+unregisterArray :: HostPtr a -> IO (Ptr a)+#if CUDA_VERSION < 4000+unregisterArray _ = requireSDK 'unregisterArray 4.0+#else+unregisterArray (HostPtr !p) = do+ status <- cuMemHostUnregister p+ resultIfOk (status,p)++{-# INLINE cuMemHostUnregister #-}+{# fun unsafe cuMemHostUnregister+ { castPtr `Ptr a' } -> `Status' cToEnum #}+#endif+++--------------------------------------------------------------------------------+-- Device Allocation+--------------------------------------------------------------------------------++-- |+-- Allocate a section of linear memory on the device, and return a reference to+-- it. The memory is sufficient to hold the given number of elements of storable+-- type. It is suitably aligned for any type, and is not cleared.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gb82d2a09844a58dd9e744dc31e8aa467>+--+{-# INLINEABLE mallocArray #-}+mallocArray :: Storable a => Int -> IO (DevicePtr a)+mallocArray = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')+ doMalloc x !n = resultIfOk =<< cuMemAlloc (n * sizeOf x)++{-# INLINE cuMemAlloc #-}+{# fun unsafe cuMemAlloc+ { alloca'- `DevicePtr a' peekDeviceHandle*+ , `Int' } -> `Status' cToEnum #}+ where+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+++-- |+-- Execute a computation on the device, passing a pointer to a temporarily+-- allocated block of memory sufficient to hold the given number of elements of+-- storable type. The memory is freed when the computation terminates (normally+-- or via an exception), so the pointer must not be used after this.+--+-- Note that kernel launches can be asynchronous, so you may want to add a+-- synchronisation point using 'Foreign.CUDA.Driver.Context.sync' as part+-- of the continuation.+--+{-# INLINEABLE allocaArray #-}+allocaArray :: Storable a => Int -> (DevicePtr a -> IO b) -> IO b+allocaArray !n = bracket (mallocArray n) free+++-- |+-- Release a section of device memory.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g89b3f154e17cc89b6eea277dbdf5c93a>+--+{-# INLINEABLE free #-}+free :: DevicePtr a -> IO ()+free !dp = nothingIfOk =<< cuMemFree dp++{-# INLINE cuMemFree #-}+{# fun unsafe cuMemFree+ { useDeviceHandle `DevicePtr a' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Unified memory allocations+--------------------------------------------------------------------------------++-- |+-- Options for unified memory allocations+--+#if CUDA_VERSION < 6000+data AttachFlag+#else+{# enum CUmemAttach_flags as AttachFlag+ { underscoreToCase }+ with prefix="CU_MEM_ATTACH_OPTION" deriving (Eq, Show, Bounded) #}+#endif++-- |+-- Allocates memory that will be automatically managed by the Unified Memory+-- system. The returned pointer is valid on the CPU and on all GPUs which+-- supported managed memory. All accesses to this pointer must obey the+-- Unified Memory programming model.+--+-- On a multi-GPU system with peer-to-peer support, where multiple GPUs+-- support managed memory, the physical storage is created on the GPU which+-- is active at the time 'mallocManagedArray' is called. All other GPUs+-- will access the array at reduced bandwidth via peer mapping over the+-- PCIe bus. The Unified Memory system does not migrate memory between+-- GPUs.+--+-- On a multi-GPU system where multiple GPUs support managed memory, but+-- not all pairs of such GPUs have peer-to-peer support between them, the+-- physical storage is allocated in system memory (zero-copy memory) and+-- all GPUs will access the data at reduced bandwidth over the PCIe bus.+--+-- Requires CUDA-6.0+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gb347ded34dc326af404aa02af5388a32>+--+{-# INLINEABLE mallocManagedArray #-}+mallocManagedArray :: Storable a => [AttachFlag] -> Int -> IO (DevicePtr a)+#if CUDA_VERSION < 6000+mallocManagedArray _ _ = requireSDK 'mallocManagedArray 6.0+#else+mallocManagedArray !flags = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')+ doMalloc x !n = resultIfOk =<< cuMemAllocManaged (n * sizeOf x) flags++{-# INLINE cuMemAllocManaged #-}+{# fun unsafe cuMemAllocManaged+ { alloca'- `DevicePtr a' peekDeviceHandle*+ , `Int'+ , combineBitMasks `[AttachFlag]' } -> `Status' cToEnum #}+ where+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+#endif+++--------------------------------------------------------------------------------+-- Marshalling+--------------------------------------------------------------------------------++-- Device -> Host+-- --------------++-- |+-- Copy a number of elements from the device to host memory. This is a+-- synchronous operation.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g3480368ee0208a98f75019c9a8450893>+--+{-# INLINEABLE peekArray #-}+peekArray :: Storable a => Int -> DevicePtr a -> Ptr a -> IO ()+peekArray !n !dptr !hptr = doPeek undefined dptr+ where+ doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPeek x _ = nothingIfOk =<< cuMemcpyDtoH hptr dptr (n * sizeOf x)++{-# INLINE cuMemcpyDtoH #-}+{# fun cuMemcpyDtoH+ { castPtr `Ptr a'+ , useDeviceHandle `DevicePtr a'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Copy memory from the device asynchronously, possibly associated with a+-- particular stream. The destination host memory must be page-locked.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g56f30236c7c5247f8e061b59d3268362>+--+{-# INLINEABLE peekArrayAsync #-}+peekArrayAsync :: Storable a => Int -> DevicePtr a -> HostPtr a -> Maybe Stream -> IO ()+peekArrayAsync !n !dptr !hptr !mst = doPeek undefined dptr+ where+ doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPeek x _ = nothingIfOk =<< cuMemcpyDtoHAsync hptr dptr (n * sizeOf x) (fromMaybe defaultStream mst)++{-# INLINE cuMemcpyDtoHAsync #-}+{# fun cuMemcpyDtoHAsync+ { useHP `HostPtr a'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+ where+ useHP = castPtr . useHostPtr+++-- |+-- Copy a 2D array from the device to the host.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>+--+{-# INLINEABLE peekArray2D #-}+peekArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> Ptr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> IO ()+peekArray2D !w !h !dptr !dw !dx !dy !hptr !hw !hx !hy = doPeek undefined dptr+ where+ doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPeek x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ in+ nothingIfOk =<< cuMemcpy2DDtoH hptr hw' hx' hy dptr dw' dx' dy w' h++{-# INLINE cuMemcpy2DDtoH #-}+{# fun cuMemcpy2DDtoH+ { castPtr `Ptr a'+ , `Int'+ , `Int'+ , `Int'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ }+ -> `Status' cToEnum #}+++-- |+-- Copy a 2D array from the device to the host asynchronously, possibly+-- associated with a particular execution stream. The destination host memory+-- must be page-locked.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>+--+{-# INLINEABLE peekArray2DAsync #-}+peekArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> HostPtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> Maybe Stream -- ^ stream to associate to+ -> IO ()+peekArray2DAsync !w !h !dptr !dw !dx !dy !hptr !hw !hx !hy !mst = doPeek undefined dptr+ where+ doPeek :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPeek x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ st = fromMaybe defaultStream mst+ in+ nothingIfOk =<< cuMemcpy2DDtoHAsync hptr hw' hx' hy dptr dw' dx' dy w' h st++{-# INLINE cuMemcpy2DDtoHAsync #-}+{# fun cuMemcpy2DDtoHAsync+ { useHP `HostPtr a'+ , `Int'+ , `Int'+ , `Int'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , useStream `Stream'+ }+ -> `Status' cToEnum #}+ where+ useHP = castPtr . useHostPtr+++-- |+-- Copy a number of elements from the device into a new Haskell list. Note that+-- this requires two memory copies: firstly from the device into a heap+-- allocated array, and from there marshalled into a list.+--+{-# INLINEABLE peekListArray #-}+peekListArray :: Storable a => Int -> DevicePtr a -> IO [a]+peekListArray !n !dptr =+ F.allocaArray n $ \p -> do+ peekArray n dptr p+ F.peekArray n p+++-- Host -> Device+-- --------------++-- |+-- Copy a number of elements onto the device. This is a synchronous operation.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4d32266788c440b0220b1a9ba5795169>+--+{-# INLINEABLE pokeArray #-}+pokeArray :: Storable a => Int -> Ptr a -> DevicePtr a -> IO ()+pokeArray !n !hptr !dptr = doPoke undefined dptr+ where+ doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPoke x _ = nothingIfOk =<< cuMemcpyHtoD dptr hptr (n * sizeOf x)++{-# INLINE cuMemcpyHtoD #-}+{# fun cuMemcpyHtoD+ { useDeviceHandle `DevicePtr a'+ , castPtr `Ptr a'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Copy memory onto the device asynchronously, possibly associated with a+-- particular stream. The source host memory must be page-locked.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g1572263fe2597d7ba4f6964597a354a3>+--+{-# INLINEABLE pokeArrayAsync #-}+pokeArrayAsync :: Storable a => Int -> HostPtr a -> DevicePtr a -> Maybe Stream -> IO ()+pokeArrayAsync !n !hptr !dptr !mst = dopoke undefined dptr+ where+ dopoke :: Storable a' => a' -> DevicePtr a' -> IO ()+ dopoke x _ = nothingIfOk =<< cuMemcpyHtoDAsync dptr hptr (n * sizeOf x) (fromMaybe defaultStream mst)++{-# INLINE cuMemcpyHtoDAsync #-}+{# fun cuMemcpyHtoDAsync+ { useDeviceHandle `DevicePtr a'+ , useHP `HostPtr a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+ where+ useHP = castPtr . useHostPtr+++-- |+-- Copy a 2D array from the host to the device.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>+--+{-# INLINEABLE pokeArray2D #-}+pokeArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> Ptr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> IO ()+pokeArray2D !w !h !hptr !hw !hx !hy !dptr !dw !dx !dy = doPoke undefined dptr+ where+ doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPoke x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ in+ nothingIfOk =<< cuMemcpy2DHtoD dptr dw' dx' dy hptr hw' hx' hy w' h++{-# INLINE cuMemcpy2DHtoD #-}+{# fun cuMemcpy2DHtoD+ { useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , castPtr `Ptr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ }+ -> `Status' cToEnum #}+++-- |+-- Copy a 2D array from the host to the device asynchronously, possibly+-- associated with a particular execution stream. The source host memory must be+-- page-locked.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>+--+{-# INLINEABLE pokeArray2DAsync #-}+pokeArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> HostPtr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> Maybe Stream -- ^ stream to associate to+ -> IO ()+pokeArray2DAsync !w !h !hptr !hw !hx !hy !dptr !dw !dx !dy !mst = doPoke undefined dptr+ where+ doPoke :: Storable a' => a' -> DevicePtr a' -> IO ()+ doPoke x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ st = fromMaybe defaultStream mst+ in+ nothingIfOk =<< cuMemcpy2DHtoDAsync dptr dw' dx' dy hptr hw' hx' hy w' h st++{-# INLINE cuMemcpy2DHtoDAsync #-}+{# fun cuMemcpy2DHtoDAsync+ { useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , useHP `HostPtr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , useStream `Stream'+ }+ -> `Status' cToEnum #}+ where+ useHP = castPtr . useHostPtr+++-- |+-- Write a list of storable elements into a device array. The device array must+-- be sufficiently large to hold the entire list. This requires two marshalling+-- operations.+--+{-# INLINEABLE pokeListArray #-}+pokeListArray :: Storable a => [a] -> DevicePtr a -> IO ()+pokeListArray !xs !dptr = F.withArrayLen xs $ \ !len !p -> pokeArray len p dptr+++-- Device -> Device+-- ----------------++-- |+-- Copy the given number of elements from the first device array (source) to the+-- second device (destination). The copied areas may not overlap. This operation+-- is asynchronous with respect to the host, but will never overlap with kernel+-- execution.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g1725774abf8b51b91945f3336b778c8b>+--+{-# INLINEABLE copyArray #-}+copyArray :: Storable a => Int -> DevicePtr a -> DevicePtr a -> IO ()+copyArray !n = docopy undefined+ where+ docopy :: Storable a' => a' -> DevicePtr a' -> DevicePtr a' -> IO ()+ docopy x src dst = nothingIfOk =<< cuMemcpyDtoD dst src (n * sizeOf x)++{-# INLINE cuMemcpyDtoD #-}+{# fun unsafe cuMemcpyDtoD+ { useDeviceHandle `DevicePtr a'+ , useDeviceHandle `DevicePtr a'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Copy the given number of elements from the first device array (source) to the+-- second device array (destination). The copied areas may not overlap. The+-- operation is asynchronous with respect to the host, and can be asynchronous+-- to other device operations by associating it with a particular stream.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g39ea09ba682b8eccc9c3e0c04319b5c8>+--+{-# INLINEABLE copyArrayAsync #-}+copyArrayAsync :: Storable a => Int -> DevicePtr a -> DevicePtr a -> Maybe Stream -> IO ()+copyArrayAsync !n !src !dst !mst = docopy undefined src+ where+ docopy :: Storable a' => a' -> DevicePtr a' -> IO ()+ docopy x _ = nothingIfOk =<< cuMemcpyDtoDAsync dst src (n * sizeOf x) (fromMaybe defaultStream mst)++{-# INLINE cuMemcpyDtoDAsync #-}+{# fun unsafe cuMemcpyDtoDAsync+ { useDeviceHandle `DevicePtr a'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Copy a 2D array from the first device array (source) to the second device+-- array (destination). The copied areas must not overlap. This operation is+-- asynchronous with respect to the host, but will never overlap with kernel+-- execution.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g27f885b30c34cc20a663a671dbf6fc27>+--+{-# INLINEABLE copyArray2D #-}+copyArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> IO ()+copyArray2D !w !h !src !hw !hx !hy !dst !dw !dx !dy = doCopy undefined dst+ where+ doCopy :: Storable a' => a' -> DevicePtr a' -> IO ()+ doCopy x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ in+ nothingIfOk =<< cuMemcpy2DDtoD dst dw' dx' dy src hw' hx' hy w' h++{-# INLINE cuMemcpy2DDtoD #-}+{# fun unsafe cuMemcpy2DDtoD+ { useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ }+ -> `Status' cToEnum #}+++-- |+-- Copy a 2D array from the first device array (source) to the second device+-- array (destination). The copied areas may not overlap. The operation is+-- asynchronous with respect to the host, and can be asynchronous to other+-- device operations by associating it with a particular execution stream.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g4acf155faeb969d9d21f5433d3d0f274>+--+{-# INLINEABLE copyArray2DAsync #-}+copyArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> Int -- ^ source x-coordinate+ -> Int -- ^ source y-coordinate+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Int -- ^ destination x-coordinate+ -> Int -- ^ destination y-coordinate+ -> Maybe Stream -- ^ stream to associate to+ -> IO ()+copyArray2DAsync !w !h !src !hw !hx !hy !dst !dw !dx !dy !mst = doCopy undefined dst+ where+ doCopy :: Storable a' => a' -> DevicePtr a' -> IO ()+ doCopy x _ =+ let bytes = sizeOf x+ w' = w * bytes+ hw' = hw * bytes+ hx' = hx * bytes+ dw' = dw * bytes+ dx' = dx * bytes+ st = fromMaybe defaultStream mst+ in+ nothingIfOk =<< cuMemcpy2DDtoDAsync dst dw' dx' dy src hw' hx' hy w' h st++{-# INLINE cuMemcpy2DDtoDAsync #-}+{# fun unsafe cuMemcpy2DDtoDAsync+ { useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , `Int'+ , useStream `Stream'+ }+ -> `Status' cToEnum #}++++-- Context -> Context+-- ------------------++-- |+-- Copies an array from device memory in one context to device memory in another+-- context. Note that this function is asynchronous with respect to the host,+-- but serialised with respect to all pending and future asynchronous work in+-- the source and destination contexts. To avoid this synchronisation, use+-- 'copyArrayPeerAsync' instead.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1ge1f5c7771544fee150ada8853c7cbf4a>+--+{-# INLINEABLE copyArrayPeer #-}+copyArrayPeer :: Storable a+ => Int -- ^ number of array elements+ -> DevicePtr a -> Context -- ^ source array and context+ -> DevicePtr a -> Context -- ^ destination array and context+ -> IO ()+#if CUDA_VERSION < 4000+copyArrayPeer _ _ _ _ _ = requireSDK 'copyArrayPeer 4.0+#else+copyArrayPeer !n !src !srcCtx !dst !dstCtx = go undefined src dst+ where+ go :: Storable b => b -> DevicePtr b -> DevicePtr b -> IO ()+ go x _ _ = nothingIfOk =<< cuMemcpyPeer dst dstCtx src srcCtx (n * sizeOf x)++{-# INLINE cuMemcpyPeer #-}+{# fun unsafe cuMemcpyPeer+ { useDeviceHandle `DevicePtr a'+ , useContext `Context'+ , useDeviceHandle `DevicePtr a'+ , useContext `Context'+ , `Int' } -> `Status' cToEnum #}+#endif+++-- |+-- Copies from device memory in one context to device memory in another context.+-- Note that this function is asynchronous with respect to the host and all work+-- in other streams and devices.+--+-- Requires CUDA-4.0.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g82fcecb38018e64b98616a8ac30112f2>+--+{-# INLINEABLE copyArrayPeerAsync #-}+copyArrayPeerAsync :: Storable a+ => Int -- ^ number of array elements+ -> DevicePtr a -> Context -- ^ source array and context+ -> DevicePtr a -> Context -- ^ destination array and device context+ -> Maybe Stream -- ^ stream to associate with+ -> IO ()+#if CUDA_VERSION < 4000+copyArrayPeerAsync _ _ _ _ _ _ = requireSDK 'copyArrayPeerAsync 4.0+#else+copyArrayPeerAsync !n !src !srcCtx !dst !dstCtx !st = go undefined src dst+ where+ go :: Storable b => b -> DevicePtr b -> DevicePtr b -> IO ()+ go x _ _ = nothingIfOk =<< cuMemcpyPeerAsync dst dstCtx src srcCtx (n * sizeOf x) stream+ stream = fromMaybe defaultStream st++{-# INLINE cuMemcpyPeerAsync #-}+{# fun unsafe cuMemcpyPeerAsync+ { useDeviceHandle `DevicePtr a'+ , useContext `Context'+ , useDeviceHandle `DevicePtr a'+ , useContext `Context'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+#endif+++--------------------------------------------------------------------------------+-- Combined Allocation and Marshalling+--------------------------------------------------------------------------------++-- |+-- Write a list of storable elements into a newly allocated device array,+-- returning the device pointer together with the number of elements that were+-- written. Note that this requires two memory copies: firstly from a Haskell+-- list to a heap allocated array, and from there onto the graphics device. The+-- memory should be 'free'd when no longer required.+--+{-# INLINEABLE newListArrayLen #-}+newListArrayLen :: Storable a => [a] -> IO (DevicePtr a, Int)+newListArrayLen xs =+ F.withArrayLen xs $ \len p ->+ bracketOnError (mallocArray len) free $ \d_xs -> do+ pokeArray len p d_xs+ return (d_xs, len)+++-- |+-- Write a list of storable elements into a newly allocated device array. This+-- is 'newListArrayLen' composed with 'fst'.+--+{-# INLINEABLE newListArray #-}+newListArray :: Storable a => [a] -> IO (DevicePtr a)+newListArray xs = fst `fmap` newListArrayLen xs+++-- |+-- Temporarily store a list of elements into a newly allocated device array. An+-- IO action is applied to to the array, the result of which is returned.+-- Similar to 'newListArray', this requires copying the data twice.+--+-- As with 'allocaArray', the memory is freed once the action completes, so you+-- should not return the pointer from the action, and be wary of asynchronous+-- kernel execution.+--+{-# INLINEABLE withListArray #-}+withListArray :: Storable a => [a] -> (DevicePtr a -> IO b) -> IO b+withListArray xs = withListArrayLen xs . const+++-- |+-- A variant of 'withListArray' which also supplies the number of elements in+-- the array to the applied function+--+{-# INLINEABLE withListArrayLen #-}+withListArrayLen :: Storable a => [a] -> (Int -> DevicePtr a -> IO b) -> IO b+withListArrayLen xs f =+ bracket (newListArrayLen xs) (free . fst) (uncurry . flip $ f)+--+-- XXX: Will this attempt to double-free the device array on error (together+-- with newListArrayLen)?+--+++--------------------------------------------------------------------------------+-- Utility+--------------------------------------------------------------------------------++-- |+-- Set a number of data elements to the specified value, which may be either 8-,+-- 16-, or 32-bits wide.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g6e582bf866e9e2fb014297bfaf354d7b>+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g7d805e610054392a4d11e8a8bf5eb35c>+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g983e8d8759acd1b64326317481fbf132>+--+{-# INLINEABLE memset #-}+memset :: Storable a => DevicePtr a -> Int -> a -> IO ()+memset !dptr !n !val = case sizeOf val of+ 1 -> nothingIfOk =<< cuMemsetD8 dptr val n+ 2 -> nothingIfOk =<< cuMemsetD16 dptr val n+ 4 -> nothingIfOk =<< cuMemsetD32 dptr val n+ _ -> cudaError "can only memset 8-, 16-, and 32-bit values"++--+-- We use unsafe coerce below to reinterpret the bits of the value to memset as,+-- into the integer type required by the setting functions.+--+{-# INLINE cuMemsetD8 #-}+{# fun unsafe cuMemsetD8+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int' } -> `Status' cToEnum #}++{-# INLINE cuMemsetD16 #-}+{# fun unsafe cuMemsetD16+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int' } -> `Status' cToEnum #}++{-# INLINE cuMemsetD32 #-}+{# fun unsafe cuMemsetD32+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Set the number of data elements to the specified value, which may be either+-- 8-, 16-, or 32-bits wide. The operation is asynchronous and may optionally be+-- associated with a stream.+--+-- Requires CUDA-3.2.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gaef08a7ccd61112f94e82f2b30d43627>+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1gf731438877dd8ec875e4c43d848c878c>+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g58229da5d30f1c0cdf667b320ec2c0f5>+--+{-# INLINEABLE memsetAsync #-}+memsetAsync :: Storable a => DevicePtr a -> Int -> a -> Maybe Stream -> IO ()+#if CUDA_VERSION < 3020+memsetAsync _ _ _ _ = requireSDK 'memsetAsync 3.2+#else+memsetAsync !dptr !n !val !mst = case sizeOf val of+ 1 -> nothingIfOk =<< cuMemsetD8Async dptr val n stream+ 2 -> nothingIfOk =<< cuMemsetD16Async dptr val n stream+ 4 -> nothingIfOk =<< cuMemsetD32Async dptr val n stream+ _ -> cudaError "can only memset 8-, 16-, and 32-bit values"+ where+ stream = fromMaybe defaultStream mst++{-# INLINE cuMemsetD8Async #-}+{# fun unsafe cuMemsetD8Async+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}++{-# INLINE cuMemsetD16Async #-}+{# fun unsafe cuMemsetD16Async+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}++{-# INLINE cuMemsetD32Async #-}+{# fun unsafe cuMemsetD32Async+ { useDeviceHandle `DevicePtr a'+ , unsafeCoerce `a'+ , `Int'+ , useStream `Stream' } -> `Status' cToEnum #}+#endif+++-- |+-- Return the device pointer associated with a mapped, pinned host buffer, which+-- was allocated with the 'DeviceMapped' option by 'mallocHostArray'.+--+-- Currently, no options are supported and this must be empty.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g57a39e5cba26af4d06be67fc77cc62f0>+--+{-# INLINEABLE getDevicePtr #-}+getDevicePtr :: [AllocFlag] -> HostPtr a -> IO (DevicePtr a)+getDevicePtr !flags !hp = resultIfOk =<< cuMemHostGetDevicePointer hp flags++{-# INLINE cuMemHostGetDevicePointer #-}+{# fun unsafe cuMemHostGetDevicePointer+ { alloca'- `DevicePtr a' peekDeviceHandle*+ , useHP `HostPtr a'+ , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}+ where+ alloca' = F.alloca+ useHP = castPtr . useHostPtr+++-- |+-- Return the base address and allocation size of the given device pointer.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g64fee5711274a2a0573a789c94d8299b>+--+{-# INLINEABLE getBasePtr #-}+getBasePtr :: DevicePtr a -> IO (DevicePtr a, Int64)+getBasePtr !dptr = do+ (status,base,size) <- cuMemGetAddressRange dptr+ resultIfOk (status, (base,size))++{-# INLINE cuMemGetAddressRange #-}+{# fun unsafe cuMemGetAddressRange+ { alloca'- `DevicePtr a' peekDeviceHandle*+ , alloca'- `Int64' peekIntConv*+ , useDeviceHandle `DevicePtr a' } -> `Status' cToEnum #}+ where+ alloca' :: Storable a => (Ptr a -> IO b) -> IO b+ alloca' = F.alloca++-- |+-- Return the amount of free and total memory respectively available to the+-- current context (bytes).+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MEM.html#group__CUDA__MEM_1g808f555540d0143a331cc42aa98835c0>+--+{-# INLINEABLE getMemInfo #-}+getMemInfo :: IO (Int64, Int64)+getMemInfo = do+ (!status,!f,!t) <- cuMemGetInfo+ resultIfOk (status,(f,t))++{-# INLINE cuMemGetInfo #-}+{# fun unsafe cuMemGetInfo+ { alloca'- `Int64' peekIntConv*+ , alloca'- `Int64' peekIntConv* } -> `Status' cToEnum #}+ where+ alloca' = F.alloca+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++type DeviceHandle = {# type CUdeviceptr #}++-- Lift an opaque handle to a typed DevicePtr representation. This occasions+-- arcane distinctions for the different driver versions and Tesla (compute 1.x)+-- and Fermi (compute 2.x) class architectures on 32- and 64-bit hosts.+--+{-# INLINE peekDeviceHandle #-}+peekDeviceHandle :: Ptr DeviceHandle -> IO (DevicePtr a)+peekDeviceHandle !p = DevicePtr . intPtrToPtr . fromIntegral <$> peek p++-- Use a device pointer as an opaque handle type+--+{-# INLINE useDeviceHandle #-}+useDeviceHandle :: DevicePtr a -> DeviceHandle+useDeviceHandle = fromIntegral . ptrToIntPtr . useDevicePtr+
+ src/Foreign/CUDA/Driver/Module.hs view
@@ -0,0 +1,20 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Module+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Module management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Module (++ module Foreign.CUDA.Driver.Module.Base,+ module Foreign.CUDA.Driver.Module.Query,++) where++import Foreign.CUDA.Driver.Module.Base hiding ( JITOptionInternal(..), useModule, jitOptionUnpack, jitTargetOfCompute )+import Foreign.CUDA.Driver.Module.Query+
+ src/Foreign/CUDA/Driver/Module/Base.chs view
@@ -0,0 +1,322 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_HADDOCK prune #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Module.Base+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Module loading for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Module.Base (++ -- * Module Management+ Module(..),+ JITOption(..), JITTarget(..), JITResult(..), JITFallback(..), JITInputType(..),+ JITOptionInternal(..),++ -- ** Loading and unloading modules+ loadFile,+ loadData, loadDataFromPtr,+ loadDataEx, loadDataFromPtrEx,+ unload,++ -- Internal+ jitOptionUnpack, jitTargetOfCompute,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Analysis.Device+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Unsafe.Coerce++import Control.Monad ( liftM )+import Data.ByteString.Char8 ( ByteString )+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Internal as B+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A reference to a Module object, containing collections of device functions+--+newtype Module = Module { useModule :: {# type CUmodule #}}+ deriving (Eq, Show)++-- |+-- Just-in-time compilation and linking options+--+data JITOption+ = MaxRegisters !Int -- ^ maximum number of registers per thread+ | ThreadsPerBlock !Int -- ^ number of threads per block to target for+ | OptimisationLevel !Int -- ^ level of optimisation to apply (1-4, default 4)+ | Target !Compute -- ^ compilation target, otherwise determined from context+ | FallbackStrategy !JITFallback -- ^ fallback strategy if matching cubin not found+ | GenerateDebugInfo -- ^ generate debug info (-g) (requires cuda >= 5.5)+ | GenerateLineInfo -- ^ generate line number information (-lineinfo) (requires cuda >= 5.5)+ | Verbose -- ^ verbose log messages (requires cuda >= 5.5)+ deriving (Show)++-- |+-- Results of online compilation+--+data JITResult = JITResult+ {+ jitTime :: !Float, -- ^ milliseconds spent compiling PTX+ jitInfoLog :: !ByteString, -- ^ information about PTX assembly+ jitModule :: !Module -- ^ the compiled module+ }+ deriving (Show)+++-- |+-- Online compilation target architecture+--+{# enum CUjit_target as JITTarget+ { underscoreToCase }+ with prefix="CU_TARGET" deriving (Eq, Show) #}++-- |+-- Online compilation fallback strategy+--+{# enum CUjit_fallback as JITFallback+ { underscoreToCase+ , CU_PREFER_PTX as PreferPTX }+ with prefix="CU" deriving (Eq, Show) #}++-- |+-- Device code formats that can be used for online linking+--+#if CUDA_VERSION < 5050+data JITInputType+#else+{# enum CUjitInputType as JITInputType+ { underscoreToCase+ , CU_JIT_INPUT_PTX as PTX }+ with prefix="CU_JIT_INPUT" deriving (Eq, Show) #}+#endif++{# enum CUjit_option as JITOptionInternal+ { }+ with prefix="CU" deriving (Eq, Show) #}+++--------------------------------------------------------------------------------+-- Module management+--------------------------------------------------------------------------------++-- |+-- Load the contents of the specified file (either a ptx or cubin file) to+-- create a new module, and load that module into the current context.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g366093bd269dafd0af21f1c7d18115d3>+--+{-# INLINEABLE loadFile #-}+loadFile :: FilePath -> IO Module+loadFile !ptx = resultIfOk =<< cuModuleLoad ptx++{-# INLINE cuModuleLoad #-}+{# fun unsafe cuModuleLoad+ { alloca- `Module' peekMod*+ , withCString* `FilePath' } -> `Status' cToEnum #}+++-- |+-- Load the contents of the given image into a new module, and load that module+-- into the current context. The image is (typically) the contents of a cubin or+-- PTX file.+--+-- Note that the 'ByteString' will be copied into a temporary staging area so+-- that it can be passed to C.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g04ce266ce03720f479eab76136b90c0b>+--+{-# INLINEABLE loadData #-}+loadData :: ByteString -> IO Module+loadData !img =+ B.useAsCString img (\p -> loadDataFromPtr (castPtr p))++-- |+-- As 'loadData', but read the image data from the given pointer. The image is a+-- NULL-terminated sequence of bytes.+--+{-# INLINEABLE loadDataFromPtr #-}+loadDataFromPtr :: Ptr Word8 -> IO Module+loadDataFromPtr !img = resultIfOk =<< cuModuleLoadData img++{-# INLINE cuModuleLoadData #-}+{# fun unsafe cuModuleLoadData+ { alloca- `Module' peekMod*+ , castPtr `Ptr Word8' } -> ` Status' cToEnum #}+++-- |+-- Load the contents of the given image into a module with online compiler+-- options, and load the module into the current context. The image is+-- (typically) the contents of a cubin or PTX file. The actual attributes of the+-- compiled kernel can be probed using 'requires'.+--+-- Note that the 'ByteString' will be copied into a temporary staging area so+-- that it can be passed to C.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g9e8047e9dbf725f0cd7cafd18bfd4d12>+--+{-# INLINEABLE loadDataEx #-}+loadDataEx :: ByteString -> [JITOption] -> IO JITResult+loadDataEx !img !options =+ B.useAsCString img (\p -> loadDataFromPtrEx (castPtr p) options)++-- |+-- As 'loadDataEx', but read the image data from the given pointer. The image is+-- a NULL-terminated sequence of bytes.+--+{-# INLINEABLE loadDataFromPtrEx #-}+loadDataFromPtrEx :: Ptr Word8 -> [JITOption] -> IO JITResult+loadDataFromPtrEx !img !options = do+ let logSize = 2048++ fp_ilog <- B.mallocByteString logSize++ allocaArray logSize $ \p_elog -> do+ withForeignPtr fp_ilog $ \p_ilog -> do++ let (opt,val) = unzip $+ [ (JIT_WALL_TIME, 0) -- must be first, this is extracted below+ , (JIT_INFO_LOG_BUFFER_SIZE_BYTES, logSize)+ , (JIT_ERROR_LOG_BUFFER_SIZE_BYTES, logSize)+ , (JIT_INFO_LOG_BUFFER, unsafeCoerce (p_ilog :: CString))+ , (JIT_ERROR_LOG_BUFFER, unsafeCoerce (p_elog :: CString))+ ]+ +++ map jitOptionUnpack options++ withArrayLen (map cFromEnum opt) $ \i p_opts -> do+ withArray (map unsafeCoerce val) $ \ p_vals -> do++ (s,mdl) <- cuModuleLoadDataEx img i p_opts p_vals++ case s of+ Success -> do+ time <- peek (castPtr p_vals)+ bytes <- c_strnlen p_ilog logSize+ let infoLog | bytes == 0 = B.empty+ | otherwise = B.fromForeignPtr (castForeignPtr fp_ilog) 0 bytes+ return $! JITResult time infoLog mdl++ _ -> do+ errLog <- peekCString p_elog+ cudaError (unlines [describe s, errLog])+++{-# INLINE cuModuleLoadDataEx #-}+{# fun unsafe cuModuleLoadDataEx+ { alloca- `Module' peekMod*+ , castPtr `Ptr Word8'+ , `Int'+ , id `Ptr CInt'+ , id `Ptr (Ptr ())' } -> `Status' cToEnum #}+++-- |+-- Unload a module from the current context.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g8ea3d716524369de3763104ced4ea57b>+--+{-# INLINEABLE unload #-}+unload :: Module -> IO ()+unload !m = nothingIfOk =<< cuModuleUnload m++{-# INLINE cuModuleUnload #-}+{# fun unsafe cuModuleUnload+ { useModule `Module' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++{-# INLINE peekMod #-}+peekMod :: Ptr {# type CUmodule #} -> IO Module+peekMod = liftM Module . peek+++{-# INLINE jitOptionUnpack #-}+jitOptionUnpack :: JITOption -> (JITOptionInternal, Int)+jitOptionUnpack (MaxRegisters x) = (JIT_MAX_REGISTERS, x)+jitOptionUnpack (ThreadsPerBlock x) = (JIT_THREADS_PER_BLOCK, x)+jitOptionUnpack (OptimisationLevel x) = (JIT_OPTIMIZATION_LEVEL, x)+jitOptionUnpack (Target x) = (JIT_TARGET, fromEnum (jitTargetOfCompute x))+jitOptionUnpack (FallbackStrategy x) = (JIT_FALLBACK_STRATEGY, fromEnum x)+#if CUDA_VERSION >= 5050+jitOptionUnpack GenerateDebugInfo = (JIT_GENERATE_DEBUG_INFO, fromEnum True)+jitOptionUnpack GenerateLineInfo = (JIT_GENERATE_LINE_INFO, fromEnum True)+jitOptionUnpack Verbose = (JIT_LOG_VERBOSE, fromEnum True)+#else+jitOptionUnpack GenerateDebugInfo = requireSDK 'GenerateDebugInfo 5.5+jitOptionUnpack GenerateLineInfo = requireSDK 'GenerateLineInfo 5.5+jitOptionUnpack Verbose = requireSDK 'Verbose 5.5+#endif+++{-# INLINE jitTargetOfCompute #-}+jitTargetOfCompute :: Compute -> JITTarget+jitTargetOfCompute (Compute 1 0) = Compute10+jitTargetOfCompute (Compute 1 1) = Compute11+jitTargetOfCompute (Compute 1 2) = Compute12+jitTargetOfCompute (Compute 1 3) = Compute13+jitTargetOfCompute (Compute 2 0) = Compute20+jitTargetOfCompute (Compute 2 1) = Compute21+#if CUDA_VERSION >= 5000+jitTargetOfCompute (Compute 3 0) = Compute30+jitTargetOfCompute (Compute 3 5) = Compute35+#endif+#if CUDA_VERSION >= 6000+jitTargetOfCompute (Compute 3 2) = Compute32+jitTargetOfCompute (Compute 5 0) = Compute50+#endif+#if CUDA_VERSION >= 6050+jitTargetOfCompute (Compute 3 7) = Compute37+#endif+#if CUDA_VERSION >= 7000+jitTargetOfCompute (Compute 5 2) = Compute52+#endif+jitTargetOfCompute compute = error ("Unknown JIT Target for Compute " ++ show compute)+++#if defined(WIN32)+{-# INLINE c_strnlen' #-}+c_strnlen' :: CString -> CSize -> IO CSize+c_strnlen' str size = do+ str' <- peekCStringLen (str, fromIntegral size)+ return $ stringLen 0 str'+ where+ stringLen acc [] = acc+ stringLen acc ('\0':_) = acc+ stringLen acc (_:xs) = stringLen (acc+1) xs+#else+foreign import ccall unsafe "string.h strnlen" c_strnlen'+ :: CString -> CSize -> IO CSize+#endif++{-# INLINE c_strnlen #-}+c_strnlen :: CString -> Int -> IO Int+c_strnlen str maxlen = cIntConv `fmap` c_strnlen' str (cIntConv maxlen)+
+ src/Foreign/CUDA/Driver/Module/Link.chs view
@@ -0,0 +1,224 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Module.Link+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Module linking for low-level driver interface+--+-- Since CUDA-5.5+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Module.Link (++ -- ** JIT module linking+ LinkState, JITOption(..), JITInputType(..),++ create, destroy, complete,+ addFile,+ addData, addDataFromPtr,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Module.Base+import Foreign.CUDA.Internal.C2HS++-- System+import Control.Monad ( liftM )+import Foreign+import Foreign.C+import Unsafe.Coerce++import Data.ByteString.Char8 ( ByteString )+import qualified Data.ByteString.Char8 as B+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A pending JIT linker state+--+#if CUDA_VERSION < 5050+data LinkState+#else+newtype LinkState = LinkState { useLinkState :: {# type CUlinkState #} }+ deriving (Show)+#endif+++--------------------------------------------------------------------------------+-- JIT linking+--------------------------------------------------------------------------------++-- |+-- Create a pending JIT linker invocation. The returned 'LinkState' should+-- be 'destroy'ed once no longer needed. The device code machine size will+-- match the calling application.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g86ca4052a2fab369cb943523908aa80d>+--+{-# INLINEABLE create #-}+create :: [JITOption] -> IO LinkState+#if CUDA_VERSION < 5050+create _ = requireSDK 'create 5.5+#else+create !options =+ let (opt,val) = unzip $ map jitOptionUnpack options+ in+ withArray (map cFromEnum opt) $ \p_opts ->+ withArray (map unsafeCoerce val) $ \p_vals ->+ resultIfOk =<< cuLinkCreate (length opt) p_opts p_vals++{-# INLINE cuLinkCreate #-}+{# fun unsafe cuLinkCreate+ { `Int'+ , id `Ptr CInt'+ , id `Ptr (Ptr ())'+ , alloca- `LinkState' peekLS* } -> `Status' cToEnum #}+ where+ peekLS = liftM LinkState . peek+#endif+++-- |+-- Destroy the state of a JIT linker invocation.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g01b7ae2a34047b05716969af245ce2d9>+--+{-# INLINEABLE destroy #-}+destroy :: LinkState -> IO ()+#if CUDA_VERSION < 5050+destroy _ = requireSDK 'destroy 5.5+#else+destroy !s = nothingIfOk =<< cuLinkDestroy s++{-# INLINE cuLinkDestroy #-}+{# fun unsafe cuLinkDestroy+ { useLinkState `LinkState' } -> `Status' cToEnum #}+#endif+++-- |+-- Complete a pending linker invocation and load the current module. The+-- link state will be destroyed.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g818fcd84a4150a997c0bba76fef4e716>+--+{-# INLINEABLE complete #-}+complete :: LinkState -> IO Module+#if CUDA_VERSION < 5050+complete _ = requireSDK 'complete 5.5+#else+complete !ls = do+ cubin <- resultIfOk =<< cuLinkComplete ls nullPtr+ mdl <- loadDataFromPtr (castPtr cubin)+ destroy ls+ return mdl++{-# INLINE cuLinkComplete #-}+{# fun unsafe cuLinkComplete+ { useLinkState `LinkState'+ , alloca- `Ptr ()' peek*+ , castPtr `Ptr Int'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Add an input file to a pending linker invocation.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g1224c0fd48d4a683f3ce19997f200a8c>+--+{-# INLINEABLE addFile #-}+addFile :: LinkState -> FilePath -> JITInputType -> [JITOption] -> IO ()+#if CUDA_VERSION < 5050+addFile _ _ _ _ = requireSDK 'addFile 5.5+#else+addFile !ls !fp !t !options =+ let (opt,val) = unzip $ map jitOptionUnpack options+ in+ withArrayLen (map cFromEnum opt) $ \i p_opts ->+ withArray (map unsafeCoerce val) $ \ p_vals ->+ nothingIfOk =<< cuLinkAddFile ls t fp i p_opts p_vals++{-# INLINE cuLinkAddFile #-}+{# fun unsafe cuLinkAddFile+ { useLinkState `LinkState'+ , cFromEnum `JITInputType'+ , withCString* `FilePath'+ , `Int'+ , id `Ptr CInt'+ , id `Ptr (Ptr ())'+ }+ -> `Status' cToEnum #}+#endif+++-- |+-- Add an input to a pending linker invocation.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g3ebcd2ccb772ba9c120937a2d2831b77>+--+{-# INLINEABLE addData #-}+addData :: LinkState -> ByteString -> JITInputType -> [JITOption] -> IO ()+#if CUDA_VERSION < 5050+addData _ _ _ = requireSDK 'addData 5.5+#else+addData !ls !img !k !options =+ B.useAsCStringLen img (\(p, n) -> addDataFromPtr ls n (castPtr p) k options)+#endif++-- |+-- As 'addData', but read the specified number of bytes of image data from+-- the given pointer.+--+{-# INLINEABLE addDataFromPtr #-}+addDataFromPtr :: LinkState -> Int -> Ptr Word8 -> JITInputType -> [JITOption] -> IO ()+#if CUDA_VERSION < 5050+addDataFromPtr _ _ _ _ = requireSDK 'addDataFromPtr 5.5+#else+addDataFromPtr !ls !n !img !t !options =+ let (opt,val) = unzip $ map jitOptionUnpack options+ in+ withArrayLen (map cFromEnum opt) $ \i p_opts ->+ withArray (map unsafeCoerce val) $ \ p_vals ->+ nothingIfOk =<< cuLinkAddData ls t img n "<unknown>" i p_opts p_vals++{-# INLINE cuLinkAddData #-}+{# fun unsafe cuLinkAddData+ { useLinkState `LinkState'+ , cFromEnum `JITInputType'+ , castPtr `Ptr Word8'+ , `Int'+ , `String'+ , `Int'+ , id `Ptr CInt'+ , id `Ptr (Ptr ())'+ }+ -> `Status' cToEnum #}+#endif+
+ src/Foreign/CUDA/Driver/Module/Query.chs view
@@ -0,0 +1,108 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Module.Query+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Querying module attributes for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Module.Query (++ -- ** Querying module inhabitants+ getFun, getPtr, getTex,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Exec+import Foreign.CUDA.Driver.Marshal ( peekDeviceHandle )+import Foreign.CUDA.Driver.Module.Base+import Foreign.CUDA.Driver.Texture+import Foreign.CUDA.Internal.C2HS+import Foreign.CUDA.Ptr++-- System+import Foreign+import Foreign.C+import Control.Exception ( throwIO )+import Control.Monad ( liftM )+++--------------------------------------------------------------------------------+-- Querying module attributes+--------------------------------------------------------------------------------++-- |+-- Returns a function handle.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1ga52be009b0d4045811b30c965e1cb2cf>+--+{-# INLINEABLE getFun #-}+getFun :: Module -> String -> IO Fun+getFun !mdl !fn = resultIfFound "function" fn =<< cuModuleGetFunction mdl fn++{-# INLINE cuModuleGetFunction #-}+{# fun unsafe cuModuleGetFunction+ { alloca- `Fun' peekFun*+ , useModule `Module'+ , withCString* `String' } -> `Status' cToEnum #}+ where peekFun = liftM Fun . peek+++-- |+-- Return a global pointer, and size of the global (in bytes).+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1gf3e43672e26073b1081476dbf47a86ab>+--+{-# INLINEABLE getPtr #-}+getPtr :: Module -> String -> IO (DevicePtr a, Int)+getPtr !mdl !name = do+ (!status,!dptr,!bytes) <- cuModuleGetGlobal mdl name+ resultIfFound "global" name (status,(dptr,bytes))++{-# INLINE cuModuleGetGlobal #-}+{# fun unsafe cuModuleGetGlobal+ { alloca- `DevicePtr a' peekDeviceHandle*+ , alloca- `Int' peekIntConv*+ , useModule `Module'+ , withCString* `String' } -> `Status' cToEnum #}+++-- |+-- Return a handle to a texture reference. This texture reference handle+-- should not be destroyed, as the texture will be destroyed automatically+-- when the module is unloaded.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__MODULE.html#group__CUDA__MODULE_1g9607dcbf911c16420d5264273f2b5608>+--+{-# INLINEABLE getTex #-}+getTex :: Module -> String -> IO Texture+getTex !mdl !name = resultIfFound "texture" name =<< cuModuleGetTexRef mdl name++{-# INLINE cuModuleGetTexRef #-}+{# fun unsafe cuModuleGetTexRef+ { alloca- `Texture' peekTex*+ , useModule `Module'+ , withCString* `String' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++{-# INLINE resultIfFound #-}+resultIfFound :: String -> String -> (Status, a) -> IO a+resultIfFound kind name (!status,!result) =+ case status of+ Success -> return result+ NotFound -> cudaError (kind ++ ' ' : describe status ++ ": " ++ name)+ _ -> throwIO (ExitCode status)+
+ src/Foreign/CUDA/Driver/Profiler.chs view
@@ -0,0 +1,100 @@+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Profiler+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Profiler control for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Profiler (++ OutputMode(..),+ initialise,+ start, stop,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- friends+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- system+import Foreign+import Foreign.C+++-- | Profiler output mode+--+{# enum CUoutput_mode as OutputMode+ { underscoreToCase+ , CU_OUT_CSV as CSV }+ with prefix="CU_OUT" deriving (Eq, Show) #}+++-- | Initialise the CUDA profiler.+--+-- The configuration file is used to specify profiling options and profiling+-- counters. Refer to the "Compute Command Line Profiler User Guide" for+-- supported profiler options and counters.+--+-- Note that the CUDA profiler can not be initialised with this function if+-- another profiling tool is already active.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER>+--+{-# INLINEABLE initialise #-}+initialise+ :: FilePath -- ^ configuration file that itemises which counters and/or options to profile+ -> FilePath -- ^ output file where profiling results will be stored+ -> OutputMode+ -> IO ()+initialise config output mode+ = nothingIfOk =<< cuProfilerInitialize config output mode++{-# INLINE cuProfilerInitialize #-}+{# fun unsafe cuProfilerInitialize+ { `String'+ , `String'+ , cFromEnum `OutputMode'+ }+ -> `Status' cToEnum #}+++-- | Begin profiling collection by the active profiling tool for the current+-- context. If profiling is already enabled, then this has no effect.+--+-- 'start' and 'stop' can be used to programatically control profiling+-- granularity, by allowing profiling to be done only on selected pieces of+-- code.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER_1g8a5314de2292c2efac83ac7fcfa9190e>+--+{-# INLINEABLE start #-}+start :: IO ()+start = nothingIfOk =<< cuProfilerStart++{-# INLINE cuProfilerStart #-}+{# fun unsafe cuProfilerStart+ { } -> `Status' cToEnum #}+++-- | Stop profiling collection by the active profiling tool for the current+-- context, and force all pending profiler events to be written to the output+-- file. If profiling is already inactive, this has no effect.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__PROFILER.html#group__CUDA__PROFILER_1g4d8edef6174fd90165e6ac838f320a5f>+--+{-# INLINEABLE stop #-}+stop :: IO ()+stop = nothingIfOk =<< cuProfilerStop++{-# INLINE cuProfilerStop #-}+{# fun unsafe cuProfilerStop+ { } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Driver/Stream.chs view
@@ -0,0 +1,167 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Stream+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Stream management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Stream (++ -- * Stream Management+ Stream(..), StreamFlag,+ create, createWithPriority, destroy, finished, block, getPriority,++ defaultStream,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Types+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad ( liftM )+import Control.Exception ( throwIO )+++--------------------------------------------------------------------------------+-- Stream management+--------------------------------------------------------------------------------++-- |+-- Create a new stream.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1ga581f0c5833e21ded8b5a56594e243f4>+--+{-# INLINEABLE create #-}+create :: [StreamFlag] -> IO Stream+create !flags = resultIfOk =<< cuStreamCreate flags++{-# INLINE cuStreamCreate #-}+{# fun unsafe cuStreamCreate+ { alloca- `Stream' peekStream*+ , combineBitMasks `[StreamFlag]' } -> `Status' cToEnum #}+ where+ peekStream = liftM Stream . peek+++-- |+-- Create a stream with the given priority. Work submitted to+-- a higher-priority stream may preempt work already executing in a lower+-- priority stream.+--+-- The convention is that lower numbers represent higher priorities. The+-- default priority is zero. The range of meaningful numeric priorities can+-- be queried using 'Foreign.CUDA.Driver.Context.Config.getStreamPriorityRange'.+-- If the specified priority is outside the supported numerical range, it+-- will automatically be clamped to the highest or lowest number in the+-- range.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g95c1a8c7c3dacb13091692dd9c7f7471>+--+{-# INLINEABLE createWithPriority #-}+createWithPriority :: StreamPriority -> [StreamFlag] -> IO Stream+#if CUDA_VERSION < 5050+createWithPriority _ _ = requireSDK 'createWithPriority 5.5+#else+createWithPriority !priority !flags = resultIfOk =<< cuStreamCreateWithPriority flags priority++{-# INLINE cuStreamCreateWithPriority #-}+{# fun unsafe cuStreamCreateWithPriority+ { alloca- `Stream' peekStream*+ , combineBitMasks `[StreamFlag]'+ , cIntConv `StreamPriority'+ }+ -> `Status' cToEnum #}+ where+ peekStream = liftM Stream . peek+#endif+++-- |+-- Destroy a stream. If the device is still doing work in the stream when+-- 'destroy' is called, the function returns immediately and the resources+-- associated with the stream will be released automatically once the+-- device has completed all work.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g244c8833de4596bcd31a06cdf21ee758>+--+{-# INLINEABLE destroy #-}+destroy :: Stream -> IO ()+destroy !st = nothingIfOk =<< cuStreamDestroy st++{-# INLINE cuStreamDestroy #-}+{# fun unsafe cuStreamDestroy+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Check if all operations in the stream have completed.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g1b0d24bbe97fa68e4bc511fb6adfeb0b>+--+{-# INLINEABLE finished #-}+finished :: Stream -> IO Bool+finished !st =+ cuStreamQuery st >>= \rv ->+ case rv of+ Success -> return True+ NotReady -> return False+ _ -> throwIO (ExitCode rv)++{-# INLINE cuStreamQuery #-}+{# fun unsafe cuStreamQuery+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Wait until the device has completed all operations in the Stream.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g15e49dd91ec15991eb7c0a741beb7dad>+--+{-# INLINEABLE block #-}+block :: Stream -> IO ()+block !st = nothingIfOk =<< cuStreamSynchronize st++{-# INLINE cuStreamSynchronize #-}+{# fun cuStreamSynchronize+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Query the priority of a stream.+--+-- Requires CUDA-5.5.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__STREAM.html#group__CUDA__STREAM_1g5bd5cb26915a2ecf1921807339488484>+--+{-# INLINEABLE getPriority #-}+getPriority :: Stream -> IO StreamPriority+#if CUDA_VERSION < 5050+getPriority _ = requireSDK 'getPriority 5.5+#else+getPriority !st = resultIfOk =<< cuStreamGetPriority st++{-# INLINE cuStreamGetPriority #-}+{# fun unsafe cuStreamGetPriority+ { useStream `Stream'+ , alloca- `StreamPriority' peekIntConv*+ }+ -> `Status' cToEnum #}+#endif+
+ src/Foreign/CUDA/Driver/Texture.chs view
@@ -0,0 +1,308 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# OPTIONS_HADDOCK prune #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Texture+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Texture management for low-level driver interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Texture (++ -- * Texture Reference Management+ Texture(..), Format(..), AddressMode(..), FilterMode(..), ReadMode(..),+ bind, bind2D,+ getAddressMode, getFilterMode, getFormat,+ setAddressMode, setFilterMode, setFormat, setReadMode,++ -- Deprecated+ create, destroy,++ -- Internal+ peekTex++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Ptr+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Driver.Marshal+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad++#if CUDA_VERSION >= 3020+{-# DEPRECATED create, destroy "as of CUDA version 3.2" #-}+#endif+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A texture reference+--+newtype Texture = Texture { useTexture :: {# type CUtexref #}}+ deriving (Eq, Show)++instance Storable Texture where+ sizeOf _ = sizeOf (undefined :: {# type CUtexref #})+ alignment _ = alignment (undefined :: {# type CUtexref #})+ peek p = Texture `fmap` peek (castPtr p)+ poke p t = poke (castPtr p) (useTexture t)++-- |+-- Texture reference addressing modes+--+{# enum CUaddress_mode as AddressMode+ { underscoreToCase }+ with prefix="CU_TR_ADDRESS_MODE" deriving (Eq, Show) #}++-- |+-- Texture reference filtering mode+--+{# enum CUfilter_mode as FilterMode+ { underscoreToCase }+ with prefix="CU_TR_FILTER_MODE" deriving (Eq, Show) #}++-- |+-- Texture read mode options+--+#c+typedef enum CUtexture_flag_enum {+ CU_TEXTURE_FLAG_READ_AS_INTEGER = CU_TRSF_READ_AS_INTEGER,+ CU_TEXTURE_FLAG_NORMALIZED_COORDINATES = CU_TRSF_NORMALIZED_COORDINATES,+ CU_TEXTURE_FLAG_SRGB = CU_TRSF_SRGB+} CUtexture_flag;+#endc++{# enum CUtexture_flag as ReadMode+ { underscoreToCase+ , CU_TEXTURE_FLAG_SRGB as SRGB }+ with prefix="CU_TEXTURE_FLAG" deriving (Eq, Show) #}++-- |+-- Texture data formats+--+{# enum CUarray_format as Format+ { underscoreToCase+ , UNSIGNED_INT8 as Word8+ , UNSIGNED_INT16 as Word16+ , UNSIGNED_INT32 as Word32+ , SIGNED_INT8 as Int8+ , SIGNED_INT16 as Int16+ , SIGNED_INT32 as Int32 }+ with prefix="CU_AD_FORMAT" deriving (Eq, Show) #}+++--------------------------------------------------------------------------------+-- Texture management+--------------------------------------------------------------------------------++-- |+-- Create a new texture reference. Once created, the application must call+-- 'setPtr' to associate the reference with allocated memory. Other texture+-- reference functions are used to specify the format and interpretation to be+-- used when the memory is read through this reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF__DEPRECATED.html#group__CUDA__TEXREF__DEPRECATED_1g0084fabe2c6d28ffcf9d9f5c7164f16c>+--+{-# INLINEABLE create #-}+create :: IO Texture+create = resultIfOk =<< cuTexRefCreate++{-# INLINE cuTexRefCreate #-}+{# fun unsafe cuTexRefCreate+ { alloca- `Texture' peekTex* } -> `Status' cToEnum #}+++-- |+-- Destroy a texture reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF__DEPRECATED.html#group__CUDA__TEXREF__DEPRECATED_1gea8edbd6cf9f97e6ab2b41fc6785519d>+--+{-# INLINEABLE destroy #-}+destroy :: Texture -> IO ()+destroy !tex = nothingIfOk =<< cuTexRefDestroy tex++{-# INLINE cuTexRefDestroy #-}+{# fun unsafe cuTexRefDestroy+ { useTexture `Texture' } -> `Status' cToEnum #}+++-- |+-- Bind a linear array address of the given size (bytes) as a texture+-- reference. Any previously bound references are unbound.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g44ef7e5055192d52b3d43456602b50a8>+--+{-# INLINEABLE bind #-}+bind :: Texture -> DevicePtr a -> Int64 -> IO ()+bind !tex !dptr !bytes = nothingIfOk =<< cuTexRefSetAddress tex dptr bytes++{-# INLINE cuTexRefSetAddress #-}+{# fun unsafe cuTexRefSetAddress+ { alloca- `Int'+ , useTexture `Texture'+ , useDeviceHandle `DevicePtr a'+ , `Int64' } -> `Status' cToEnum #}+++-- |+-- Bind a linear address range to the given texture reference as a+-- two-dimensional arena. Any previously bound reference is unbound. Note that+-- calls to 'setFormat' can not follow a call to 'bind2D' for the same texture+-- reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g26f709bbe10516681913d1ffe8756ee2>+--+{-# INLINEABLE bind2D #-}+bind2D :: Texture -> Format -> Int -> DevicePtr a -> (Int,Int) -> Int64 -> IO ()+bind2D !tex !fmt !chn !dptr (!width,!height) !pitch =+ nothingIfOk =<< cuTexRefSetAddress2DSimple tex fmt chn dptr width height pitch++{-# INLINE cuTexRefSetAddress2DSimple #-}+{# fun unsafe cuTexRefSetAddress2DSimple+ { useTexture `Texture'+ , cFromEnum `Format'+ , `Int'+ , useDeviceHandle `DevicePtr a'+ , `Int'+ , `Int'+ , `Int64' } -> `Status' cToEnum #}+++-- |+-- Get the addressing mode used by a texture reference, corresponding to the+-- given dimension (currently the only supported dimension values are 0 or 1).+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1gfb367d93dc1d20aab0cf8ce70d543b33>+--+{-# INLINEABLE getAddressMode #-}+getAddressMode :: Texture -> Int -> IO AddressMode+getAddressMode !tex !dim = resultIfOk =<< cuTexRefGetAddressMode tex dim++{-# INLINE cuTexRefGetAddressMode #-}+{# fun unsafe cuTexRefGetAddressMode+ { alloca- `AddressMode' peekEnum*+ , useTexture `Texture'+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Get the filtering mode used by a texture reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g2439e069746f69b940f2f4dbc78cdf87>+--+{-# INLINEABLE getFilterMode #-}+getFilterMode :: Texture -> IO FilterMode+getFilterMode !tex = resultIfOk =<< cuTexRefGetFilterMode tex++{-# INLINE cuTexRefGetFilterMode #-}+{# fun unsafe cuTexRefGetFilterMode+ { alloca- `FilterMode' peekEnum*+ , useTexture `Texture' } -> `Status' cToEnum #}+++-- |+-- Get the data format and number of channel components of the bound texture.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g90936eb6c7c4434a609e1160c278ae53>+--+{-# INLINEABLE getFormat #-}+getFormat :: Texture -> IO (Format, Int)+getFormat !tex = do+ (!status,!fmt,!dim) <- cuTexRefGetFormat tex+ resultIfOk (status,(fmt,dim))++{-# INLINE cuTexRefGetFormat #-}+{# fun unsafe cuTexRefGetFormat+ { alloca- `Format' peekEnum*+ , alloca- `Int' peekIntConv*+ , useTexture `Texture' } -> `Status' cToEnum #}+++-- |+-- Specify the addressing mode for the given dimension of a texture reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g85f4a13eeb94c8072f61091489349bcb>+--+{-# INLINEABLE setAddressMode #-}+setAddressMode :: Texture -> Int -> AddressMode -> IO ()+setAddressMode !tex !dim !mode = nothingIfOk =<< cuTexRefSetAddressMode tex dim mode++{-# INLINE cuTexRefSetAddressMode #-}+{# fun unsafe cuTexRefSetAddressMode+ { useTexture `Texture'+ , `Int'+ , cFromEnum `AddressMode' } -> `Status' cToEnum #}+++-- |+-- Specify the filtering mode to be used when reading memory through a texture+-- reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g595d0af02c55576f8c835e4efd1f39c0>+--+{-# INLINEABLE setFilterMode #-}+setFilterMode :: Texture -> FilterMode -> IO ()+setFilterMode !tex !mode = nothingIfOk =<< cuTexRefSetFilterMode tex mode++{-# INLINE cuTexRefSetFilterMode #-}+{# fun unsafe cuTexRefSetFilterMode+ { useTexture `Texture'+ , cFromEnum `FilterMode' } -> `Status' cToEnum #}+++-- |+-- Specify additional characteristics for reading and indexing the texture+-- reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g554ffd896487533c36810f2e45bb7a28>+--+{-# INLINEABLE setReadMode #-}+setReadMode :: Texture -> ReadMode -> IO ()+setReadMode !tex !mode = nothingIfOk =<< cuTexRefSetFlags tex mode++{-# INLINE cuTexRefSetFlags #-}+{# fun unsafe cuTexRefSetFlags+ { useTexture `Texture'+ , cFromEnum `ReadMode' } -> `Status' cToEnum #}+++-- |+-- Specify the format of the data and number of packed components per element to+-- be read by the texture reference.+--+-- <http://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__TEXREF.html#group__CUDA__TEXREF_1g05585ef8ea2fec728a03c6c8f87cf07a>+--+{-# INLINEABLE setFormat #-}+setFormat :: Texture -> Format -> Int -> IO ()+setFormat !tex !fmt !chn = nothingIfOk =<< cuTexRefSetFormat tex fmt chn++{-# INLINE cuTexRefSetFormat #-}+{# fun unsafe cuTexRefSetFormat+ { useTexture `Texture'+ , cFromEnum `Format'+ , `Int' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++{-# INLINE peekTex #-}+peekTex :: Ptr {# type CUtexref #} -> IO Texture+peekTex = liftM Texture . peek+
+ src/Foreign/CUDA/Driver/Utils.chs view
@@ -0,0 +1,40 @@+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Utils+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Utility functions+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Driver.Utils (++ driverVersion,++) where++#include "cbits/stubs.h"+{# context lib="cuda" #}++-- Friends+import Foreign.CUDA.Driver.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+++-- |+-- Return the version number of the installed CUDA driver.+--+{-# INLINEABLE driverVersion #-}+driverVersion :: IO Int+driverVersion = resultIfOk =<< cuDriverGetVersion++{-# INLINE cuDriverGetVersion #-}+{# fun unsafe cuDriverGetVersion+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Internal/C2HS.hs view
@@ -0,0 +1,230 @@+-- C->Haskell Compiler: Marshalling library+--+-- Copyright (c) [1999...2005] Manuel M T Chakravarty+--+-- Redistribution and use in source and binary forms, with or without+-- modification, are permitted provided that the following conditions are met:+--+-- 1. Redistributions of source code must retain the above copyright notice,+-- this list of conditions and the following disclaimer.+-- 2. Redistributions in binary form must reproduce the above copyright+-- notice, this list of conditions and the following disclaimer in the+-- documentation and/or other materials provided with the distribution.+-- 3. The name of the author may not be used to endorse or promote products+-- derived from this software without specific prior written permission.+--+-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+-- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN+-- NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED+-- TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+-- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+-- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+--+--- Description ---------------------------------------------------------------+--+-- Language: Haskell 98+--+-- This module provides the marshaling routines for Haskell files produced by+-- C->Haskell for binding to C library interfaces. It exports all of the+-- low-level FFI (language-independent plus the C-specific parts) together+-- with the C->HS-specific higher-level marshalling routines.+--++module Foreign.CUDA.Internal.C2HS (++ -- * Composite marshalling functions+ withCStringLenIntConv, peekCStringLenIntConv, withIntConv, withFloatConv,+ peekIntConv, peekFloatConv, withBool, peekBool, withEnum, peekEnum,+ peekArrayWith,++ -- * Conditional results using 'Maybe'+ nothingIf, nothingIfNull,++ -- * Bit masks+ combineBitMasks, containsBitMask, extractBitMasks,++ -- * Conversion between C and Haskell types+ cIntConv, cFloatConv, cToBool, cFromBool, cToEnum, cFromEnum+) where+++import Foreign+import Foreign.C+import Control.Monad ( liftM )+++-- Composite marshalling functions+-- -------------------------------++-- Strings with explicit length+--+withCStringLenIntConv :: String -> (CStringLen -> IO a) -> IO a+withCStringLenIntConv s f = withCStringLen s $ \(p, n) -> f (p, cIntConv n)++peekCStringLenIntConv :: CStringLen -> IO String+peekCStringLenIntConv (s, n) = peekCStringLen (s, cIntConv n)++-- Marshalling of numerals+--++withIntConv :: (Storable b, Integral a, Integral b) => a -> (Ptr b -> IO c) -> IO c+withIntConv = with . cIntConv++withFloatConv :: (Storable b, RealFloat a, RealFloat b) => a -> (Ptr b -> IO c) -> IO c+withFloatConv = with . cFloatConv++peekIntConv :: (Storable a, Integral a, Integral b) => Ptr a -> IO b+peekIntConv = liftM cIntConv . peek++peekFloatConv :: (Storable a, RealFloat a, RealFloat b) => Ptr a -> IO b+peekFloatConv = liftM cFloatConv . peek++-- Passing Booleans by reference+--++withBool :: (Integral a, Storable a) => Bool -> (Ptr a -> IO b) -> IO b+withBool = with . fromBool++peekBool :: (Integral a, Storable a) => Ptr a -> IO Bool+peekBool = liftM toBool . peek+++-- Read and marshal array elements+--++peekArrayWith :: Storable a => (a -> b) -> Int -> Ptr a -> IO [b]+peekArrayWith f n p = map f `fmap` peekArray n p+++-- Passing enums by reference+--++withEnum :: (Enum a, Integral b, Storable b) => a -> (Ptr b -> IO c) -> IO c+withEnum = with . cFromEnum++peekEnum :: (Enum a, Integral b, Storable b) => Ptr b -> IO a+peekEnum = liftM cToEnum . peek+++{-+-- Storing of 'Maybe' values+-- -------------------------++instance Storable a => Storable (Maybe a) where+ sizeOf _ = sizeOf (undefined :: Ptr ())+ alignment _ = alignment (undefined :: Ptr ())++ peek p = do+ ptr <- peek (castPtr p)+ if ptr == nullPtr+ then return Nothing+ else liftM Just $ peek ptr++ poke p v = do+ ptr <- case v of+ Nothing -> return nullPtr+ Just v' -> new v'+ poke (castPtr p) ptr+-}+++-- Conditional results using 'Maybe'+-- ---------------------------------++-- Wrap the result into a 'Maybe' type.+--+-- * the predicate determines when the result is considered to be non-existing,+-- ie, it is represented by `Nothing'+--+-- * the second argument allows to map a result wrapped into `Just' to some+-- other domain+--+nothingIf :: (a -> Bool) -> (a -> b) -> a -> Maybe b+nothingIf p f x = if p x then Nothing else Just $ f x++-- |Instance for special casing null pointers.+--+nothingIfNull :: (Ptr a -> b) -> Ptr a -> Maybe b+nothingIfNull = nothingIf (== nullPtr)+++-- Support for bit masks+-- ---------------------++-- Given a list of enumeration values that represent bit masks, combine these+-- masks using bitwise disjunction.+--+combineBitMasks :: (Enum a, Num b, Bits b) => [a] -> b+combineBitMasks = foldl (.|.) 0 . map (fromIntegral . fromEnum)++-- Tests whether the given bit mask is contained in the given bit pattern+-- (i.e., all bits set in the mask are also set in the pattern).+--+containsBitMask :: (Num a, Bits a, Enum b) => a -> b -> Bool+bits `containsBitMask` bm = let bm' = fromIntegral . fromEnum $ bm+ in+ bm' .&. bits == bm'++-- |Given a bit pattern, yield all bit masks that it contains.+--+-- * This does *not* attempt to compute a minimal set of bit masks that when+-- combined yield the bit pattern, instead all contained bit masks are+-- produced.+--+extractBitMasks :: (Num a, Bits a, Enum b, Bounded b) => a -> [b]+extractBitMasks bits =+ [bm | bm <- [minBound..maxBound], bits `containsBitMask` bm]+++-- Conversion routines+-- -------------------++-- |Integral conversion+--+{-# INLINE [1] cIntConv #-}+cIntConv :: (Integral a, Integral b) => a -> b+cIntConv = fromIntegral++-- |Floating conversion+--+{-# INLINE [1] cFloatConv #-}+cFloatConv :: (RealFloat a, RealFloat b) => a -> b+cFloatConv = realToFrac+-- As this conversion by default goes via `Rational', it can be very slow...+{-# RULES+ "cFloatConv/Float->Float" forall (x::Float). cFloatConv x = x;+ "cFloatConv/Double->Double" forall (x::Double). cFloatConv x = x;+ "cFloatConv/Float->CFloat" forall (x::Float). cFloatConv x = CFloat x;+ "cFloatConv/CFloat->Float" forall (x::Float). cFloatConv CFloat x = x;+ "cFloatConv/Double->CDouble" forall (x::Double). cFloatConv x = CDouble x;+ "cFloatConv/CDouble->Double" forall (x::Double). cFloatConv CDouble x = x+ #-}++-- |Obtain C value from Haskell 'Bool'.+--+{-# INLINE [1] cFromBool #-}+cFromBool :: Num a => Bool -> a+cFromBool = fromBool++-- |Obtain Haskell 'Bool' from C value.+--+{-# INLINE [1] cToBool #-}+cToBool :: (Eq a, Num a) => a -> Bool+cToBool = toBool++-- |Convert a C enumeration to Haskell.+--+{-# INLINE [1] cToEnum #-}+cToEnum :: (Integral i, Enum e) => i -> e+cToEnum = toEnum . cIntConv++-- |Convert a Haskell enumeration to C.+--+{-# INLINE [1] cFromEnum #-}+cFromEnum :: (Enum e, Integral i) => e -> i+cFromEnum = cIntConv . fromEnum+
+ src/Foreign/CUDA/Ptr.hs view
@@ -0,0 +1,184 @@+{-# LANGUAGE BangPatterns #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Ptr+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Data pointers on the host and device. These can be shared freely between the+-- CUDA runtime and Driver APIs.+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Ptr (++ -- * Device pointers+ DevicePtr(..),+ withDevicePtr,+ devPtrToWordPtr,+ wordPtrToDevPtr,+ nullDevPtr,+ castDevPtr,+ plusDevPtr,+ alignDevPtr,+ minusDevPtr,+ advanceDevPtr,++ -- * Host pointers+ HostPtr(..),+ withHostPtr,+ nullHostPtr,+ castHostPtr,+ plusHostPtr,+ alignHostPtr,+ minusHostPtr,+ advanceHostPtr,++) where++-- friends+import Foreign.CUDA.Types++-- system+import Foreign.Ptr+import Foreign.Storable+++--------------------------------------------------------------------------------+-- Device Pointer+--------------------------------------------------------------------------------++-- |+-- Look at the contents of device memory. This takes an IO action that will be+-- applied to that pointer, the result of which is returned. It would be silly+-- to return the pointer from the action.+--+{-# INLINEABLE withDevicePtr #-}+withDevicePtr :: DevicePtr a -> (Ptr a -> IO b) -> IO b+withDevicePtr !p !f = f (useDevicePtr p)++-- |+-- Return a unique handle associated with the given device pointer+--+{-# INLINEABLE devPtrToWordPtr #-}+devPtrToWordPtr :: DevicePtr a -> WordPtr+devPtrToWordPtr = ptrToWordPtr . useDevicePtr++-- |+-- Return a device pointer from the given handle+--+{-# INLINEABLE wordPtrToDevPtr #-}+wordPtrToDevPtr :: WordPtr -> DevicePtr a+wordPtrToDevPtr = DevicePtr . wordPtrToPtr++-- |+-- The constant 'nullDevPtr' contains the distinguished memory location that is+-- not associated with a valid memory location+--+{-# INLINEABLE nullDevPtr #-}+nullDevPtr :: DevicePtr a+nullDevPtr = DevicePtr nullPtr++-- |+-- Cast a device pointer from one type to another+--+{-# INLINEABLE castDevPtr #-}+castDevPtr :: DevicePtr a -> DevicePtr b+castDevPtr (DevicePtr !p) = DevicePtr (castPtr p)++-- |+-- Advance the pointer address by the given offset in bytes.+--+{-# INLINEABLE plusDevPtr #-}+plusDevPtr :: DevicePtr a -> Int -> DevicePtr a+plusDevPtr (DevicePtr !p) !d = DevicePtr (p `plusPtr` d)++-- |+-- Given an alignment constraint, align the device pointer to the next highest+-- address satisfying the constraint+--+{-# INLINEABLE alignDevPtr #-}+alignDevPtr :: DevicePtr a -> Int -> DevicePtr a+alignDevPtr (DevicePtr !p) !i = DevicePtr (p `alignPtr` i)++-- |+-- Compute the difference between the second and first argument. This fulfils+-- the relation+--+-- > p2 == p1 `plusDevPtr` (p2 `minusDevPtr` p1)+--+{-# INLINEABLE minusDevPtr #-}+minusDevPtr :: DevicePtr a -> DevicePtr a -> Int+minusDevPtr (DevicePtr !a) (DevicePtr !b) = a `minusPtr` b++-- |+-- Advance a pointer into a device array by the given number of elements+--+{-# INLINEABLE advanceDevPtr #-}+advanceDevPtr :: Storable a => DevicePtr a -> Int -> DevicePtr a+advanceDevPtr = doAdvance undefined+ where+ doAdvance :: Storable a' => a' -> DevicePtr a' -> Int -> DevicePtr a'+ doAdvance x !p !i = p `plusDevPtr` (i * sizeOf x)+++--------------------------------------------------------------------------------+-- Host Pointer+--------------------------------------------------------------------------------++-- |+-- Apply an IO action to the memory reference living inside the host pointer+-- object. All uses of the pointer should be inside the 'withHostPtr' bracket.+--+{-# INLINEABLE withHostPtr #-}+withHostPtr :: HostPtr a -> (Ptr a -> IO b) -> IO b+withHostPtr !p !f = f (useHostPtr p)+++-- |+-- The constant 'nullHostPtr' contains the distinguished memory location that is+-- not associated with a valid memory location+--+{-# INLINEABLE nullHostPtr #-}+nullHostPtr :: HostPtr a+nullHostPtr = HostPtr nullPtr++-- |+-- Cast a host pointer from one type to another+--+{-# INLINEABLE castHostPtr #-}+castHostPtr :: HostPtr a -> HostPtr b+castHostPtr (HostPtr !p) = HostPtr (castPtr p)++-- |+-- Advance the pointer address by the given offset in bytes+--+{-# INLINEABLE plusHostPtr #-}+plusHostPtr :: HostPtr a -> Int -> HostPtr a+plusHostPtr (HostPtr !p) !d = HostPtr (p `plusPtr` d)++-- |+-- Given an alignment constraint, align the host pointer to the next highest+-- address satisfying the constraint+--+{-# INLINEABLE alignHostPtr #-}+alignHostPtr :: HostPtr a -> Int -> HostPtr a+alignHostPtr (HostPtr !p) !i = HostPtr (p `alignPtr` i)++-- |+-- Compute the difference between the second and first argument+--+{-# INLINEABLE minusHostPtr #-}+minusHostPtr :: HostPtr a -> HostPtr a -> Int+minusHostPtr (HostPtr !a) (HostPtr !b) = a `minusPtr` b++-- |+-- Advance a pointer into a host array by a given number of elements+--+{-# INLINEABLE advanceHostPtr #-}+advanceHostPtr :: Storable a => HostPtr a -> Int -> HostPtr a+advanceHostPtr = doAdvance undefined+ where+ doAdvance :: Storable a' => a' -> HostPtr a' -> Int -> HostPtr a'+ doAdvance x !p !i = p `plusHostPtr` (i * sizeOf x)+
+ src/Foreign/CUDA/Runtime.hs view
@@ -0,0 +1,28 @@+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Top level bindings to the C-for-CUDA runtime API+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime (++ module Foreign.CUDA.Ptr,+ module Foreign.CUDA.Runtime.Device,+ module Foreign.CUDA.Runtime.Error,+ module Foreign.CUDA.Runtime.Exec,+ module Foreign.CUDA.Runtime.Marshal,+ module Foreign.CUDA.Runtime.Utils++) where++import Foreign.CUDA.Ptr+import Foreign.CUDA.Runtime.Device+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Runtime.Exec+import Foreign.CUDA.Runtime.Marshal+import Foreign.CUDA.Runtime.Utils+
+ src/Foreign/CUDA/Runtime/Device.chs view
@@ -0,0 +1,464 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Device+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Device management routines+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Device (++ -- * Device Management+ Device, DeviceFlag(..), DeviceProperties(..), Compute(..), ComputeMode(..),+ choose, get, count, props, set, setFlags, setOrder, reset, sync,++ -- * Peer Access+ PeerFlag,+ accessible, add, remove,++ -- * Cache Configuration+ Limit(..),+ getLimit, setLimit++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Analysis.Device+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C++#c+typedef struct cudaDeviceProp cudaDeviceProp;++typedef enum+{+ cudaDeviceFlagScheduleAuto = cudaDeviceScheduleAuto,+ cudaDeviceFlagScheduleSpin = cudaDeviceScheduleSpin,+ cudaDeviceFlagScheduleYield = cudaDeviceScheduleYield,+ cudaDeviceFlagBlockingSync = cudaDeviceBlockingSync,+ cudaDeviceFlagMapHost = cudaDeviceMapHost,+#if CUDART_VERSION >= 3000+ cudaDeviceFlagLMemResizeToMax = cudaDeviceLmemResizeToMax+#endif+} cudaDeviceFlags;+#endc+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A device identifier+--+type Device = Int++{# pointer *cudaDeviceProp as ^ foreign -> DeviceProperties nocode #}++-- |+-- Device execution flags+--+{# enum cudaDeviceFlags as DeviceFlag { }+ with prefix="cudaDeviceFlag" deriving (Eq, Show, Bounded) #}+++instance Storable DeviceProperties where+ sizeOf _ = {#sizeof cudaDeviceProp#}+ alignment _ = alignment (undefined :: Ptr ())++ poke _ _ = error "no instance for Foreign.Storable.poke DeviceProperties"+ peek p = do+ n <- peekCString =<< {#get cudaDeviceProp.name#} p+ gm <- cIntConv `fmap` {#get cudaDeviceProp.totalGlobalMem#} p+ sm <- cIntConv `fmap` {#get cudaDeviceProp.sharedMemPerBlock#} p+ rb <- cIntConv `fmap` {#get cudaDeviceProp.regsPerBlock#} p+ ws <- cIntConv `fmap` {#get cudaDeviceProp.warpSize#} p+ mp <- cIntConv `fmap` {#get cudaDeviceProp.memPitch#} p+ tb <- cIntConv `fmap` {#get cudaDeviceProp.maxThreadsPerBlock#} p+ cl <- cIntConv `fmap` {#get cudaDeviceProp.clockRate#} p+ cm <- cIntConv `fmap` {#get cudaDeviceProp.totalConstMem#} p+ v1 <- fromIntegral `fmap` {#get cudaDeviceProp.major#} p+ v2 <- fromIntegral `fmap` {#get cudaDeviceProp.minor#} p+ ta <- cIntConv `fmap` {#get cudaDeviceProp.textureAlignment#} p+ ov <- cToBool `fmap` {#get cudaDeviceProp.deviceOverlap#} p+ pc <- cIntConv `fmap` {#get cudaDeviceProp.multiProcessorCount#} p+ ke <- cToBool `fmap` {#get cudaDeviceProp.kernelExecTimeoutEnabled#} p+ tg <- cToBool `fmap` {#get cudaDeviceProp.integrated#} p+ hm <- cToBool `fmap` {#get cudaDeviceProp.canMapHostMemory#} p+ md <- cToEnum `fmap` {#get cudaDeviceProp.computeMode#} p+#if CUDART_VERSION >= 3000+ ck <- cToBool `fmap` {#get cudaDeviceProp.concurrentKernels#} p+ u1 <- cIntConv `fmap` {#get cudaDeviceProp.maxTexture1D#} p+#endif+#if CUDART_VERSION >= 3010+ ee <- cToBool `fmap` {#get cudaDeviceProp.ECCEnabled#} p+#endif+#if CUDART_VERSION >= 4000+ ae <- cIntConv `fmap` {#get cudaDeviceProp.asyncEngineCount#} p+ l2 <- cIntConv `fmap` {#get cudaDeviceProp.l2CacheSize#} p+ tm <- cIntConv `fmap` {#get cudaDeviceProp.maxThreadsPerMultiProcessor#} p+ mw <- cIntConv `fmap` {#get cudaDeviceProp.memoryBusWidth#} p+ mc <- cIntConv `fmap` {#get cudaDeviceProp.memoryClockRate#} p+ pb <- cIntConv `fmap` {#get cudaDeviceProp.pciBusID#} p+ pd <- cIntConv `fmap` {#get cudaDeviceProp.pciDeviceID#} p+ pm <- cIntConv `fmap` {#get cudaDeviceProp.pciDomainID#} p+ tc <- cToBool `fmap` {#get cudaDeviceProp.tccDriver#} p+ ua <- cToBool `fmap` {#get cudaDeviceProp.unifiedAddressing#} p+#endif+ [t1,t2,t3] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxThreadsDim#} p+ [g1,g2,g3] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxGridSize#} p+#if CUDART_VERSION >= 3000+ [u21,u22] <- peekArrayWith cIntConv 2 =<< {#get cudaDeviceProp.maxTexture2D#} p+ [u31,u32,u33] <- peekArrayWith cIntConv 3 =<< {#get cudaDeviceProp.maxTexture3D#} p+#endif+#if CUDART_VERSION >= 5050+ sp <- cToBool `fmap` {#get cudaDeviceProp.streamPrioritiesSupported#} p+#endif+#if CUDART_VERSION >= 6000+ gl1 <- cToBool `fmap` {#get cudaDeviceProp.globalL1CacheSupported#} p+ ll1 <- cToBool `fmap` {#get cudaDeviceProp.localL1CacheSupported#} p+ mm <- cToBool `fmap` {#get cudaDeviceProp.managedMemory#} p+ mg <- cToBool `fmap` {#get cudaDeviceProp.isMultiGpuBoard#} p+ mid <- cIntConv `fmap` {#get cudaDeviceProp.multiGpuBoardGroupID#} p+#endif++ return DeviceProperties+ {+ deviceName = n+ , computeCapability = Compute v1 v2+ , totalGlobalMem = gm+ , totalConstMem = cm+ , sharedMemPerBlock = sm+ , regsPerBlock = rb+ , warpSize = ws+ , maxThreadsPerBlock = tb+ , maxBlockSize = (t1,t2,t3)+ , maxGridSize = (g1,g2,g3)+ , clockRate = cl+ , multiProcessorCount = pc+ , memPitch = mp+ , textureAlignment = ta+ , computeMode = md+ , deviceOverlap = ov+ , kernelExecTimeoutEnabled = ke+ , integrated = tg+ , canMapHostMemory = hm+#if CUDART_VERSION >= 3000+ , concurrentKernels = ck+ , maxTextureDim1D = u1+ , maxTextureDim2D = (u21,u22)+ , maxTextureDim3D = (u31,u32,u33)+#endif+#if CUDART_VERSION >= 3010+ , eccEnabled = ee+#endif+#if CUDART_VERSION >= 3000 && CUDART_VERSION < 3010+ -- not visible from CUDA runtime API 3.0+ , eccEnabled = False+#endif+#if CUDART_VERSION >= 4000+ , asyncEngineCount = ae+ , cacheMemL2 = l2+ , maxThreadsPerMultiProcessor = tm+ , memBusWidth = mw+ , memClockRate = mc+ , tccDriverEnabled = tc+ , unifiedAddressing = ua+ , pciInfo = PCI pb pd pm+#endif+#if CUDA_VERSION >= 5050+ , streamPriorities = sp+#endif+#if CUDA_VERSION >= 6000+ , globalL1Cache = gl1+ , localL1Cache = ll1+ , managedMemory = mm+ , multiGPUBoard = mg+ , multiGPUBoardGroupID = mid+#endif+ }+++--------------------------------------------------------------------------------+-- Device Management+--------------------------------------------------------------------------------++-- |+-- Select the compute device which best matches the given criteria+--+{-# INLINEABLE choose #-}+choose :: DeviceProperties -> IO Device+choose !dev = resultIfOk =<< cudaChooseDevice dev++{-# INLINE cudaChooseDevice #-}+{# fun unsafe cudaChooseDevice+ { alloca- `Int' peekIntConv*+ , withDevProp* `DeviceProperties' } -> `Status' cToEnum #}+ where+ withDevProp = with+++-- |+-- Returns which device is currently being used+--+{-# INLINEABLE get #-}+get :: IO Device+get = resultIfOk =<< cudaGetDevice++{-# INLINE cudaGetDevice #-}+{# fun unsafe cudaGetDevice+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+++-- |+-- Returns the number of devices available for execution, with compute+-- capability >= 1.0+--+{-# INLINEABLE count #-}+count :: IO Int+count = resultIfOk =<< cudaGetDeviceCount++{-# INLINE cudaGetDeviceCount #-}+{# fun unsafe cudaGetDeviceCount+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+++-- |+-- Return information about the selected compute device+--+{-# INLINEABLE props #-}+props :: Device -> IO DeviceProperties+props !n = resultIfOk =<< cudaGetDeviceProperties n++{-# INLINE cudaGetDeviceProperties #-}+{# fun unsafe cudaGetDeviceProperties+ { alloca- `DeviceProperties' peek*+ , `Int' } -> `Status' cToEnum #}+++-- |+-- Set device to be used for GPU execution+--+{-# INLINEABLE set #-}+set :: Device -> IO ()+set !n = nothingIfOk =<< cudaSetDevice n++{-# INLINE cudaSetDevice #-}+{# fun unsafe cudaSetDevice+ { `Int' } -> `Status' cToEnum #}+++-- |+-- Set flags to be used for device executions+--+{-# INLINEABLE setFlags #-}+setFlags :: [DeviceFlag] -> IO ()+setFlags !f = nothingIfOk =<< cudaSetDeviceFlags (combineBitMasks f)++{-# INLINE cudaSetDeviceFlags #-}+{# fun unsafe cudaSetDeviceFlags+ { `Int' } -> `Status' cToEnum #}+++-- |+-- Set list of devices for CUDA execution in priority order+--+{-# INLINEABLE setOrder #-}+setOrder :: [Device] -> IO ()+setOrder !l = nothingIfOk =<< cudaSetValidDevices l (length l)++{-# INLINE cudaSetValidDevices #-}+{# fun unsafe cudaSetValidDevices+ { withArrayIntConv* `[Int]'+ , `Int' } -> `Status' cToEnum #}+ where+ withArrayIntConv = withArray . map cIntConv++-- |+-- Block until the device has completed all preceding requested tasks. Returns+-- an error if one of the tasks fails.+--+{-# INLINEABLE sync #-}+sync :: IO ()+#if CUDART_VERSION < 4000+{-# INLINE cudaThreadSynchronize #-}+sync = nothingIfOk =<< cudaThreadSynchronize+{# fun cudaThreadSynchronize { } -> `Status' cToEnum #}+#else+{-# INLINE cudaDeviceSynchronize #-}+sync = nothingIfOk =<< cudaDeviceSynchronize+{# fun cudaDeviceSynchronize { } -> `Status' cToEnum #}+#endif++-- |+-- Explicitly destroys and cleans up all runtime resources associated with the+-- current device in the current process. Any subsequent API call will+-- reinitialise the device.+--+-- Note that this function will reset the device immediately. It is the caller’s+-- responsibility to ensure that the device is not being accessed by any other+-- host threads from the process when this function is called.+--+{-# INLINEABLE reset #-}+reset :: IO ()+#if CUDART_VERSION >= 4000+{-# INLINE cudaDeviceReset #-}+reset = nothingIfOk =<< cudaDeviceReset+{# fun unsafe cudaDeviceReset { } -> `Status' cToEnum #}+#else+{-# INLINE cudaThreadExit #-}+reset = nothingIfOk =<< cudaThreadExit+{# fun unsafe cudaThreadExit { } -> `Status' cToEnum #}+#endif+++--------------------------------------------------------------------------------+-- Peer Access+--------------------------------------------------------------------------------++-- |+-- Possible option values for direct peer memory access+--+data PeerFlag+instance Enum PeerFlag where+#ifdef USE_EMPTY_CASE+ toEnum x = case x of {}+ fromEnum x = case x of {}+#endif++-- |+-- Queries if the first device can directly access the memory of the second. If+-- direct access is possible, it can then be enabled with 'add'. Requires+-- cuda-4.0.+--+{-# INLINEABLE accessible #-}+accessible :: Device -> Device -> IO Bool+#if CUDART_VERSION < 4000+accessible _ _ = requireSDK 'accessible 4.0+#else+accessible !dev !peer = resultIfOk =<< cudaDeviceCanAccessPeer dev peer++{-# INLINE cudaDeviceCanAccessPeer #-}+{# fun unsafe cudaDeviceCanAccessPeer+ { alloca- `Bool' peekBool*+ , cIntConv `Device'+ , cIntConv `Device' } -> `Status' cToEnum #}+#endif++-- |+-- If the devices of both the current and supplied contexts support unified+-- addressing, then enable allocations in the supplied context to be accessible+-- by the current context. Requires cuda-4.0.+--+{-# INLINEABLE add #-}+add :: Device -> [PeerFlag] -> IO ()+#if CUDART_VERSION < 4000+add _ _ = requireSDK 'add 4.0+#else+add !dev !flags = nothingIfOk =<< cudaDeviceEnablePeerAccess dev flags++{-# INLINE cudaDeviceEnablePeerAccess #-}+{# fun unsafe cudaDeviceEnablePeerAccess+ { cIntConv `Device'+ , combineBitMasks `[PeerFlag]' } -> `Status' cToEnum #}+#endif+++-- |+-- Disable direct memory access from the current context to the supplied+-- context. Requires cuda-4.0.+--+{-# INLINEABLE remove #-}+remove :: Device -> IO ()+#if CUDART_VERSION < 4000+remove _ = requireSDK 'remove 4.0+#else+remove !dev = nothingIfOk =<< cudaDeviceDisablePeerAccess dev++{-# INLINE cudaDeviceDisablePeerAccess #-}+{# fun unsafe cudaDeviceDisablePeerAccess+ { cIntConv `Device' } -> `Status' cToEnum #}+#endif+++--------------------------------------------------------------------------------+-- Cache Configuration+--------------------------------------------------------------------------------++-- |+-- Device limit flags+--+#if CUDART_VERSION < 3010+data Limit+#else+{# enum cudaLimit as Limit+ { underscoreToCase }+ with prefix="cudaLimit" deriving (Eq, Show) #}+#endif+++-- |+-- Query compute 2.0 call stack limits. Requires cuda-3.1.+--+{-# INLINEABLE getLimit #-}+getLimit :: Limit -> IO Int+#if CUDART_VERSION < 3010+getLimit _ = requireSDK 'getLimit 3.1+#elif CUDART_VERSION < 4000+getLimit !l = resultIfOk =<< cudaThreadGetLimit l++{-# INLINE cudaThreadGetLimit #-}+{# fun unsafe cudaThreadGetLimit+ { alloca- `Int' peekIntConv*+ , cFromEnum `Limit' } -> `Status' cToEnum #}+#else+getLimit !l = resultIfOk =<< cudaDeviceGetLimit l++{-# INLINE cudaDeviceGetLimit #-}+{# fun unsafe cudaDeviceGetLimit+ { alloca- `Int' peekIntConv*+ , cFromEnum `Limit' } -> `Status' cToEnum #}+#endif+++-- |+-- Set compute 2.0 call stack limits. Requires cuda-3.1.+--+{-# INLINEABLE setLimit #-}+setLimit :: Limit -> Int -> IO ()+#if CUDART_VERSION < 3010+setLimit _ _ = requireSDK 'setLimit 3.1+#elif CUDART_VERSION < 4000+setLimit !l !n = nothingIfOk =<< cudaThreadSetLimit l n++{-# INLINE cudaThreadSetLimit #-}+{# fun unsafe cudaThreadSetLimit+ { cFromEnum `Limit'+ , cIntConv `Int' } -> `Status' cToEnum #}+#else+setLimit !l !n = nothingIfOk =<< cudaDeviceSetLimit l n++{-# INLINE cudaDeviceSetLimit #-}+{# fun unsafe cudaDeviceSetLimit+ { cFromEnum `Limit'+ , cIntConv `Int' } -> `Status' cToEnum #}+#endif+
+ src/Foreign/CUDA/Runtime/Error.chs view
@@ -0,0 +1,119 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Error+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Error handling functions+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Error (++ Status(..), CUDAException(..),++ cudaError, describe, requireSDK,+ resultIfOk, nothingIfOk++) where++-- Friends+import Foreign.CUDA.Internal.C2HS+import Text.Show.Describe++-- System+import Control.Exception+import Data.Typeable+import Foreign.C+import Foreign.Ptr+import Language.Haskell.TH+import System.IO.Unsafe+import Text.Printf++#include "cbits/stubs.h"+{# context lib="cudart" #}+++--------------------------------------------------------------------------------+-- Return Status+--------------------------------------------------------------------------------++-- |+-- Return codes from API functions+--+{# enum cudaError as Status+ { cudaSuccess as Success }+ with prefix="cudaError" deriving (Eq, Show) #}++--------------------------------------------------------------------------------+-- Exceptions+--------------------------------------------------------------------------------++data CUDAException+ = ExitCode Status+ | UserError String+ deriving Typeable++instance Exception CUDAException++instance Show CUDAException where+ showsPrec _ (ExitCode s) = showString ("CUDA Exception: " ++ describe s)+ showsPrec _ (UserError s) = showString ("CUDA Exception: " ++ s)+++-- |+-- Raise a 'CUDAException' in the IO Monad+--+cudaError :: String -> IO a+cudaError s = throwIO (UserError s)++-- |+-- A specially formatted error message+--+requireSDK :: Name -> Double -> IO a+requireSDK n v = cudaError $ printf "'%s' requires at least cuda-%3.1f\n" (show n) v+++--------------------------------------------------------------------------------+-- Helper Functions+--------------------------------------------------------------------------------++-- |+-- Return the descriptive string associated with a particular error code+--+instance Describe Status where+ describe = cudaGetErrorString++-- Logically, this must be a pure function, returning a pointer to a statically+-- defined string constant.+--+{# fun pure unsafe cudaGetErrorString+ { cFromEnum `Status' } -> `String' #}+++-- |+-- Return the results of a function on successful execution, otherwise return+-- the error string associated with the return code+--+{-# INLINE resultIfOk #-}+resultIfOk :: (Status, a) -> IO a+resultIfOk (status, !result) =+ case status of+ Success -> return result+ _ -> throwIO (ExitCode status)+++-- |+-- Return the error string associated with an unsuccessful return code,+-- otherwise Nothing+--+{-# INLINE nothingIfOk #-}+nothingIfOk :: Status -> IO ()+nothingIfOk status =+ case status of+ Success -> return ()+ _ -> throwIO (ExitCode status)+
+ src/Foreign/CUDA/Runtime/Event.chs view
@@ -0,0 +1,148 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Driver.Event+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Event management for C-for-CUDA runtime environment+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Event (++ -- * Event Management+ Event, EventFlag(..), WaitFlag,+ create, destroy, elapsedTime, query, record, wait, block++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Types+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad ( liftM )+import Control.Exception ( throwIO )+import Data.Maybe ( fromMaybe )+++--------------------------------------------------------------------------------+-- Event management+--------------------------------------------------------------------------------++-- |+-- Create a new event+--+{-# INLINEABLE create #-}+create :: [EventFlag] -> IO Event+create !flags = resultIfOk =<< cudaEventCreateWithFlags flags++{-# INLINE cudaEventCreateWithFlags #-}+{# fun unsafe cudaEventCreateWithFlags+ { alloca- `Event' peekEvt*+ , combineBitMasks `[EventFlag]' } -> `Status' cToEnum #}+ where peekEvt = liftM Event . peek+++-- |+-- Destroy an event+--+{-# INLINEABLE destroy #-}+destroy :: Event -> IO ()+destroy !ev = nothingIfOk =<< cudaEventDestroy ev++{-# INLINE cudaEventDestroy #-}+{# fun unsafe cudaEventDestroy+ { useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Determine the elapsed time (in milliseconds) between two events+--+{-# INLINEABLE elapsedTime #-}+elapsedTime :: Event -> Event -> IO Float+elapsedTime !ev1 !ev2 = resultIfOk =<< cudaEventElapsedTime ev1 ev2++{-# INLINE cudaEventElapsedTime #-}+{# fun unsafe cudaEventElapsedTime+ { alloca- `Float' peekFloatConv*+ , useEvent `Event'+ , useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Determines if a event has actually been recorded+--+{-# INLINEABLE query #-}+query :: Event -> IO Bool+query !ev =+ cudaEventQuery ev >>= \rv ->+ case rv of+ Success -> return True+ NotReady -> return False+ _ -> throwIO (ExitCode rv)++{-# INLINE cudaEventQuery #-}+{# fun unsafe cudaEventQuery+ { useEvent `Event' } -> `Status' cToEnum #}+++-- |+-- Record an event once all operations in the current context (or optionally+-- specified stream) have completed. This operation is asynchronous.+--+{-# INLINEABLE record #-}+record :: Event -> Maybe Stream -> IO ()+record !ev !mst =+ nothingIfOk =<< cudaEventRecord ev (maybe defaultStream id mst)++{-# INLINE cudaEventRecord #-}+{# fun unsafe cudaEventRecord+ { useEvent `Event'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Makes all future work submitted to the (optional) stream wait until the given+-- event reports completion before beginning execution. Synchronisation is+-- performed on the device, including when the event and stream are from+-- different device contexts. Requires cuda-3.2.+--+{-# INLINEABLE wait #-}+wait :: Event -> Maybe Stream -> [WaitFlag] -> IO ()+#if CUDART_VERSION < 3020+wait _ _ _ = requireSDK 'wait 3.2+#else+wait !ev !mst !flags =+ let st = fromMaybe defaultStream mst+ in nothingIfOk =<< cudaStreamWaitEvent st ev flags++{-# INLINE cudaStreamWaitEvent #-}+{# fun unsafe cudaStreamWaitEvent+ { useStream `Stream'+ , useEvent `Event'+ , combineBitMasks `[WaitFlag]' } -> `Status' cToEnum #}+#endif++-- |+-- Wait until the event has been recorded+--+{-# INLINEABLE block #-}+block :: Event -> IO ()+block !ev = nothingIfOk =<< cudaEventSynchronize ev++{-# INLINE cudaEventSynchronize #-}+{# fun cudaEventSynchronize+ { useEvent `Event' } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Runtime/Exec.chs view
@@ -0,0 +1,276 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Exec+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Kernel execution control for C-for-CUDA runtime interface+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Exec (++ -- * Kernel Execution+ Fun, FunAttributes(..), FunParam(..), CacheConfig(..),+ attributes, setConfig, setParams, setCacheConfig, launch, launchKernel,++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Runtime.Stream ( Stream(..), defaultStream )+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad++#c+typedef struct cudaFuncAttributes cudaFuncAttributes;+#endc+++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |+-- A @__global__@ device function.+--+-- Note that the use of a string naming a function was deprecated in CUDA 4.1+-- and removed in CUDA 5.0.+--+#if CUDART_VERSION >= 5000+type Fun = FunPtr ()+#else+type Fun = String+#endif+++--+-- Function Attributes+--+{# pointer *cudaFuncAttributes as ^ foreign -> FunAttributes nocode #}++data FunAttributes = FunAttributes+ {+ constSizeBytes :: !Int64,+ localSizeBytes :: !Int64,+ sharedSizeBytes :: !Int64,+ maxKernelThreadsPerBlock :: !Int, -- ^ maximum block size that can be successively launched (based on register usage)+ numRegs :: !Int -- ^ number of registers required for each thread+ }+ deriving (Show)++instance Storable FunAttributes where+ sizeOf _ = {# sizeof cudaFuncAttributes #}+ alignment _ = alignment (undefined :: Ptr ())++ poke _ _ = error "Can not poke Foreign.CUDA.Runtime.FunAttributes"+ peek p = do+ cs <- cIntConv `fmap` {#get cudaFuncAttributes.constSizeBytes#} p+ ls <- cIntConv `fmap` {#get cudaFuncAttributes.localSizeBytes#} p+ ss <- cIntConv `fmap` {#get cudaFuncAttributes.sharedSizeBytes#} p+ tb <- cIntConv `fmap` {#get cudaFuncAttributes.maxThreadsPerBlock#} p+ nr <- cIntConv `fmap` {#get cudaFuncAttributes.numRegs#} p++ return FunAttributes+ {+ constSizeBytes = cs,+ localSizeBytes = ls,+ sharedSizeBytes = ss,+ maxKernelThreadsPerBlock = tb,+ numRegs = nr+ }++#if CUDART_VERSION < 3000+data CacheConfig+#else+-- |+-- Cache configuration preference+--+{# enum cudaFuncCache as CacheConfig+ { }+ with prefix="cudaFuncCachePrefer" deriving (Eq, Show) #}+#endif++-- |+-- Kernel function parameters. Doubles will be converted to an internal float+-- representation on devices that do not support doubles natively.+--+data FunParam where+ IArg :: !Int -> FunParam+ FArg :: !Float -> FunParam+ DArg :: !Double -> FunParam+ VArg :: Storable a => !a -> FunParam+++--------------------------------------------------------------------------------+-- Execution Control+--------------------------------------------------------------------------------++-- |+-- Obtain the attributes of the named @__global__@ device function. This+-- itemises the requirements to successfully launch the given kernel.+--+{-# INLINEABLE attributes #-}+attributes :: Fun -> IO FunAttributes+attributes !fn = resultIfOk =<< cudaFuncGetAttributes fn++{-# INLINE cudaFuncGetAttributes #-}+{# fun unsafe cudaFuncGetAttributes+ { alloca- `FunAttributes' peek*+ , withFun* `Fun' } -> `Status' cToEnum #}+++-- |+-- Specify the grid and block dimensions for a device call. Used in conjunction+-- with 'setParams', this pushes data onto the execution stack that will be+-- popped when a function is 'launch'ed.+--+{-# INLINEABLE setConfig #-}+setConfig :: (Int,Int) -- ^ grid dimensions+ -> (Int,Int,Int) -- ^ block dimensions+ -> Int64 -- ^ shared memory per block (bytes)+ -> Maybe Stream -- ^ associated processing stream+ -> IO ()+setConfig (!gx,!gy) (!bx,!by,!bz) !sharedMem !mst =+ nothingIfOk =<<+ cudaConfigureCallSimple gx gy bx by bz sharedMem (maybe defaultStream id mst)+++--+-- The FFI does not support passing deferenced structures to C functions, as+-- this is highly platform/compiler dependent. Wrap our own function stub+-- accepting plain integers.+--+{-# INLINE cudaConfigureCallSimple #-}+{# fun unsafe cudaConfigureCallSimple+ { `Int', `Int'+ , `Int', `Int', `Int'+ , cIntConv `Int64'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Set the argument parameters that will be passed to the next kernel+-- invocation. This is used in conjunction with 'setConfig' to control kernel+-- execution.+--+{-# INLINEABLE setParams #-}+setParams :: [FunParam] -> IO ()+setParams = foldM_ k 0+ where+ k !offset !arg = do+ let s = size arg+ set arg s offset >>= nothingIfOk+ return (offset + s)++ size (IArg _) = sizeOf (undefined :: Int)+ size (FArg _) = sizeOf (undefined :: Float)+ size (DArg _) = sizeOf (undefined :: Double)+ size (VArg a) = sizeOf a++ set (IArg v) s o = cudaSetupArgument v s o+ set (FArg v) s o = cudaSetupArgument v s o+ set (VArg v) s o = cudaSetupArgument v s o+ set (DArg v) s o =+ cudaSetDoubleForDevice v >>= resultIfOk >>= \d ->+ cudaSetupArgument d s o+++{-# INLINE cudaSetupArgument #-}+{# fun unsafe cudaSetupArgument+ `Storable a' =>+ { with'* `a'+ , `Int'+ , `Int' } -> `Status' cToEnum #}+ where+ with' v a = with v $ \p -> a (castPtr p)++{-# INLINE cudaSetDoubleForDevice #-}+{# fun unsafe cudaSetDoubleForDevice+ { with'* `Double' peek'* } -> `Status' cToEnum #}+ where+ with' v a = with v $ \p -> a (castPtr p)+ peek' = peek . castPtr+++-- |+-- On devices where the L1 cache and shared memory use the same hardware+-- resources, this sets the preferred cache configuration for the given device+-- function. This is only a preference; the driver is free to choose a different+-- configuration as required to execute the function.+--+-- Switching between configuration modes may insert a device-side+-- synchronisation point for streamed kernel launches+--+{-# INLINEABLE setCacheConfig #-}+setCacheConfig :: Fun -> CacheConfig -> IO ()+#if CUDART_VERSION < 3000+setCacheConfig _ _ = requireSDK 'setCacheConfig 3.0+#else+setCacheConfig !fn !pref = nothingIfOk =<< cudaFuncSetCacheConfig fn pref++{-# INLINE cudaFuncSetCacheConfig #-}+{# fun unsafe cudaFuncSetCacheConfig+ { withFun* `Fun'+ , cFromEnum `CacheConfig' } -> `Status' cToEnum #}+#endif+++-- |+-- Invoke the @__global__@ kernel function on the device. This must be preceded+-- by a call to 'setConfig' and (if appropriate) 'setParams'.+--+{-# INLINEABLE launch #-}+launch :: Fun -> IO ()+launch !fn = nothingIfOk =<< cudaLaunch fn++{-# INLINE cudaLaunch #-}+{# fun unsafe cudaLaunch+ { withFun* `Fun' } -> `Status' cToEnum #}+++-- |+-- Invoke a kernel on a @(gx * gy)@ grid of blocks, where each block contains+-- @(tx * ty * tz)@ threads and has access to a given number of bytes of shared+-- memory. The launch may also be associated with a specific 'Stream'.+--+{-# INLINEABLE launchKernel #-}+launchKernel+ :: Fun -- ^ Device function symbol+ -> (Int,Int) -- ^ grid dimensions+ -> (Int,Int,Int) -- ^ thread block shape+ -> Int64 -- ^ shared memory per block (bytes)+ -> Maybe Stream -- ^ (optional) execution stream+ -> [FunParam]+ -> IO ()+launchKernel !fn !grid !block !sm !mst !args = do+ setConfig grid block sm mst+ setParams args+ launch fn++--------------------------------------------------------------------------------+-- Internals+--------------------------------------------------------------------------------++-- CUDA 5.0 changed the type of a kernel function from char* to void*+--+#if CUDART_VERSION >= 5000+withFun :: Fun -> (Ptr a -> IO b) -> IO b+withFun fn action = action (castFunPtrToPtr fn)+#else+withFun :: Fun -> (Ptr CChar -> IO a) -> IO a+withFun = withCString+#endif+
+ src/Foreign/CUDA/Runtime/Marshal.chs view
@@ -0,0 +1,648 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE TemplateHaskell #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Marshal+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Memory management for CUDA devices+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Marshal (++ -- * Host Allocation+ AllocFlag(..),+ mallocHostArray, freeHost,++ -- * Device Allocation+ mallocArray, allocaArray, free,++ -- * Unified Memory Allocation+ AttachFlag(..),+ mallocManagedArray,++ -- * Marshalling+ peekArray, peekArrayAsync, peekArray2D, peekArray2DAsync, peekListArray,+ pokeArray, pokeArrayAsync, pokeArray2D, pokeArray2DAsync, pokeListArray,+ copyArray, copyArrayAsync, copyArray2D, copyArray2DAsync,++ -- * Combined Allocation and Marshalling+ newListArray, newListArrayLen,+ withListArray, withListArrayLen,++ -- * Utility+ memset++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Ptr+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Runtime.Stream+import Foreign.CUDA.Internal.C2HS++-- System+import Data.Int+import Data.Maybe+import Control.Exception++import Foreign.C+import Foreign.Ptr+import Foreign.Storable+import qualified Foreign.Marshal as F++#c+typedef enum cudaMemHostAlloc_option_enum {+// CUDA_MEMHOSTALLOC_OPTION_DEFAULT = cudaHostAllocDefault,+ CUDA_MEMHOSTALLOC_OPTION_DEVICE_MAPPED = cudaHostAllocMapped,+ CUDA_MEMHOSTALLOC_OPTION_PORTABLE = cudaHostAllocPortable,+ CUDA_MEMHOSTALLOC_OPTION_WRITE_COMBINED = cudaHostAllocWriteCombined+} cudaMemHostAlloc_option;+#endc++#if CUDART_VERSION >= 6000+#c+typedef enum cudaMemAttachFlags_option_enum {+ CUDA_MEM_ATTACH_OPTION_GLOBAL = cudaMemAttachGlobal,+ CUDA_MEM_ATTACH_OPTION_HOST = cudaMemAttachHost,+ CUDA_MEM_ATTACH_OPTION_SINGLE = cudaMemAttachSingle+} cudaMemAttachFlags_option;+#endc+#endif+++--------------------------------------------------------------------------------+-- Host Allocation+--------------------------------------------------------------------------------++-- |+-- Options for host allocation+--+{# enum cudaMemHostAlloc_option as AllocFlag+ { underscoreToCase }+ with prefix="CUDA_MEMHOSTALLOC_OPTION" deriving (Eq, Show, Bounded) #}+++-- |+-- Allocate a section of linear memory on the host which is page-locked and+-- directly accessible from the device. The storage is sufficient to hold the+-- given number of elements of a storable type. The runtime system automatically+-- accelerates calls to functions such as 'peekArrayAsync' and 'pokeArrayAsync'+-- that refer to page-locked memory.+--+-- Note that since the amount of pageable memory is thusly reduced, overall+-- system performance may suffer. This is best used sparingly to allocate+-- staging areas for data exchange+--+{-# INLINEABLE mallocHostArray #-}+mallocHostArray :: Storable a => [AllocFlag] -> Int -> IO (HostPtr a)+mallocHostArray !flags = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (HostPtr a')+ doMalloc x !n = resultIfOk =<< cudaHostAlloc (fromIntegral n * fromIntegral (sizeOf x)) flags++{-# INLINE cudaHostAlloc #-}+{# fun unsafe cudaHostAlloc+ { alloca'- `HostPtr a' hptr*+ , cIntConv `Int64'+ , combineBitMasks `[AllocFlag]' } -> `Status' cToEnum #}+ where+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+ hptr !p = (HostPtr . castPtr) `fmap` peek p+++-- |+-- Free page-locked host memory previously allocated with 'mallecHost'+--+{-# INLINEABLE freeHost #-}+freeHost :: HostPtr a -> IO ()+freeHost !p = nothingIfOk =<< cudaFreeHost p++{-# INLINE cudaFreeHost #-}+{# fun unsafe cudaFreeHost+ { hptr `HostPtr a' } -> `Status' cToEnum #}+ where hptr = castPtr . useHostPtr+++--------------------------------------------------------------------------------+-- Device Allocation+--------------------------------------------------------------------------------++-- |+-- Allocate a section of linear memory on the device, and return a reference to+-- it. The memory is sufficient to hold the given number of elements of storable+-- type. It is suitable aligned, and not cleared.+--+{-# INLINEABLE mallocArray #-}+mallocArray :: Storable a => Int -> IO (DevicePtr a)+mallocArray = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')+ doMalloc x !n = resultIfOk =<< cudaMalloc (fromIntegral n * fromIntegral (sizeOf x))++{-# INLINE cudaMalloc #-}+{# fun unsafe cudaMalloc+ { alloca'- `DevicePtr a' dptr*+ , cIntConv `Int64' } -> `Status' cToEnum #}+ where+ -- C-> Haskell doesn't like qualified imports in marshaller specifications+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+ dptr !p = (castDevPtr . DevicePtr) `fmap` peek p+++-- |+-- Execute a computation, passing a pointer to a temporarily allocated block of+-- memory sufficient to hold the given number of elements of storable type. The+-- memory is freed when the computation terminates (normally or via an+-- exception), so the pointer must not be used after this.+--+-- Note that kernel launches can be asynchronous, so you may need to add a+-- synchronisation point at the end of the computation.+--+{-# INLINEABLE allocaArray #-}+allocaArray :: Storable a => Int -> (DevicePtr a -> IO b) -> IO b+allocaArray n = bracket (mallocArray n) free+++-- |+-- Free previously allocated memory on the device+--+{-# INLINEABLE free #-}+free :: DevicePtr a -> IO ()+free !p = nothingIfOk =<< cudaFree p++{-# INLINE cudaFree #-}+{# fun unsafe cudaFree+ { dptr `DevicePtr a' } -> `Status' cToEnum #}+ where+ dptr = useDevicePtr . castDevPtr+++--------------------------------------------------------------------------------+-- Unified memory allocation+--------------------------------------------------------------------------------++-- |+-- Options for unified memory allocations+--+#if CUDART_VERSION >= 6000+{# enum cudaMemAttachFlags_option as AttachFlag+ { underscoreToCase }+ with prefix="CUDA_MEM_ATTACH_OPTION" deriving (Eq, Show, Bounded) #}+#else+data AttachFlag+#endif++-- |+-- Allocates memory that will be automatically managed by the Unified Memory+-- system+--+{-# INLINEABLE mallocManagedArray #-}+mallocManagedArray :: Storable a => [AttachFlag] -> Int -> IO (DevicePtr a)+#if CUDART_VERSION < 6000+mallocManagedArray _ _ = requireSDK 'mallocManagedArray 6.0+#else+mallocManagedArray !flags = doMalloc undefined+ where+ doMalloc :: Storable a' => a' -> Int -> IO (DevicePtr a')+ doMalloc x !n = resultIfOk =<< cudaMallocManaged (fromIntegral n * fromIntegral (sizeOf x)) flags++{-# INLINE cudaMallocManaged #-}+{# fun unsafe cudaMallocManaged+ { alloca'- `DevicePtr a' dptr*+ , cIntConv `Int64'+ , combineBitMasks `[AttachFlag]' } -> `Status' cToEnum #}+ where+ alloca' !f = F.alloca $ \ !p -> poke p nullPtr >> f (castPtr p)+ dptr !p = (castDevPtr . DevicePtr) `fmap` peek p+#endif+++--------------------------------------------------------------------------------+-- Marshalling+--------------------------------------------------------------------------------++-- |+-- Copy a number of elements from the device to host memory. This is a+-- synchronous operation.+--+{-# INLINEABLE peekArray #-}+peekArray :: Storable a => Int -> DevicePtr a -> Ptr a -> IO ()+peekArray !n !dptr !hptr = memcpy hptr (useDevicePtr dptr) n DeviceToHost+++-- |+-- Copy memory from the device asynchronously, possibly associated with a+-- particular stream. The destination memory must be page locked.+--+{-# INLINEABLE peekArrayAsync #-}+peekArrayAsync :: Storable a => Int -> DevicePtr a -> HostPtr a -> Maybe Stream -> IO ()+peekArrayAsync !n !dptr !hptr !mst =+ memcpyAsync (useHostPtr hptr) (useDevicePtr dptr) n DeviceToHost mst+++-- |+-- Copy a 2D memory area from the device to the host. This is a synchronous+-- operation.+--+{-# INLINEABLE peekArray2D #-}+peekArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> Ptr a -- ^ destination array+ -> Int -- ^ destination array width+ -> IO ()+peekArray2D !w !h !dptr !dw !hptr !hw =+ memcpy2D hptr hw (useDevicePtr dptr) dw w h DeviceToHost+++-- |+-- Copy a 2D memory area from the device to the host asynchronously, possibly+-- associated with a particular stream. The destination array must be page+-- locked.+--+{-# INLINEABLE peekArray2DAsync #-}+peekArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> HostPtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Maybe Stream+ -> IO ()+peekArray2DAsync !w !h !dptr !dw !hptr !hw !mst =+ memcpy2DAsync (useHostPtr hptr) hw (useDevicePtr dptr) dw w h DeviceToHost mst+++-- |+-- Copy a number of elements from the device into a new Haskell list. Note that+-- this requires two memory copies: firstly from the device into a heap+-- allocated array, and from there marshalled into a list+--+{-# INLINEABLE peekListArray #-}+peekListArray :: Storable a => Int -> DevicePtr a -> IO [a]+peekListArray !n !dptr =+ F.allocaArray n $ \p -> do+ peekArray n dptr p+ F.peekArray n p+++-- |+-- Copy a number of elements onto the device. This is a synchronous operation.+--+{-# INLINEABLE pokeArray #-}+pokeArray :: Storable a => Int -> Ptr a -> DevicePtr a -> IO ()+pokeArray !n !hptr !dptr = memcpy (useDevicePtr dptr) hptr n HostToDevice+++-- |+-- Copy memory onto the device asynchronously, possibly associated with a+-- particular stream. The source memory must be page-locked.+--+{-# INLINEABLE pokeArrayAsync #-}+pokeArrayAsync :: Storable a => Int -> HostPtr a -> DevicePtr a -> Maybe Stream -> IO ()+pokeArrayAsync !n !hptr !dptr !mst =+ memcpyAsync (useDevicePtr dptr) (useHostPtr hptr) n HostToDevice mst+++-- |+-- Copy a 2D memory area onto the device. This is a synchronous operation.+--+{-# INLINEABLE pokeArray2D #-}+pokeArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> Ptr a -- ^ source array+ -> Int -- ^ source array width+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> IO ()+pokeArray2D !w !h !hptr !dw !dptr !hw =+ memcpy2D (useDevicePtr dptr) dw hptr hw w h HostToDevice+++-- |+-- Copy a 2D memory area onto the device asynchronously, possibly associated+-- with a particular stream. The source array must be page locked.+--+{-# INLINEABLE pokeArray2DAsync #-}+pokeArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> HostPtr a -- ^ source array+ -> Int -- ^ source array width+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Maybe Stream+ -> IO ()+pokeArray2DAsync !w !h !hptr !hw !dptr !dw !mst =+ memcpy2DAsync (useDevicePtr dptr) dw (useHostPtr hptr) hw w h HostToDevice mst++-- |+-- Write a list of storable elements into a device array. The array must be+-- sufficiently large to hold the entire list. This requires two marshalling+-- operations+--+{-# INLINEABLE pokeListArray #-}+pokeListArray :: Storable a => [a] -> DevicePtr a -> IO ()+pokeListArray !xs !dptr = F.withArrayLen xs $ \len p -> pokeArray len p dptr+++-- |+-- Copy the given number of elements from the first device array (source) to the+-- second (destination). The copied areas may not overlap. This operation is+-- asynchronous with respect to host, but will not overlap other device+-- operations.+--+{-# INLINEABLE copyArray #-}+copyArray :: Storable a => Int -> DevicePtr a -> DevicePtr a -> IO ()+copyArray !n !src !dst = memcpy (useDevicePtr dst) (useDevicePtr src) n DeviceToDevice+++-- |+-- Copy the given number of elements from the first device array (source) to the+-- second (destination). The copied areas may not overlap. This operation is+-- asynchronous with respect to the host, and may be associated with a+-- particular stream.+--+{-# INLINEABLE copyArrayAsync #-}+copyArrayAsync :: Storable a => Int -> DevicePtr a -> DevicePtr a -> Maybe Stream -> IO ()+copyArrayAsync !n !src !dst !mst =+ memcpyAsync (useDevicePtr dst) (useDevicePtr src) n DeviceToDevice mst+++-- |+-- Copy a 2D memory area from the first device array (source) to the second+-- (destination). The copied areas may not overlap. This operation is+-- asynchronous with respect to the host, but will not overlap other device+-- operations.+--+{-# INLINEABLE copyArray2D #-}+copyArray2D+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> IO ()+copyArray2D !w !h !src !sw !dst !dw =+ memcpy2D (useDevicePtr dst) dw (useDevicePtr src) sw w h DeviceToDevice+++-- |+-- Copy a 2D memory area from the first device array (source) to the second+-- device array (destination). The copied areas may not overlay. This operation+-- is asynchronous with respect to the host, and may be associated with a+-- particular stream.+--+{-# INLINEABLE copyArray2DAsync #-}+copyArray2DAsync+ :: Storable a+ => Int -- ^ width to copy (elements)+ -> Int -- ^ height to copy (elements)+ -> DevicePtr a -- ^ source array+ -> Int -- ^ source array width+ -> DevicePtr a -- ^ destination array+ -> Int -- ^ destination array width+ -> Maybe Stream+ -> IO ()+copyArray2DAsync !w !h !src !sw !dst !dw !mst =+ memcpy2DAsync (useDevicePtr dst) dw (useDevicePtr src) sw w h DeviceToDevice mst+++--+-- Memory copy kind+--+{# enum cudaMemcpyKind as CopyDirection {}+ with prefix="cudaMemcpy" deriving (Eq, Show) #}++-- |+-- Copy data between host and device. This is a synchronous operation.+--+{-# INLINEABLE memcpy #-}+memcpy :: Storable a+ => Ptr a -- ^ destination+ -> Ptr a -- ^ source+ -> Int -- ^ number of elements+ -> CopyDirection+ -> IO ()+memcpy !dst !src !n !dir = doMemcpy undefined dst+ where+ doMemcpy :: Storable a' => a' -> Ptr a' -> IO ()+ doMemcpy x _ =+ nothingIfOk =<< cudaMemcpy dst src (fromIntegral n * fromIntegral (sizeOf x)) dir++{-# INLINE cudaMemcpy #-}+{# fun cudaMemcpy+ { castPtr `Ptr a'+ , castPtr `Ptr a'+ , cIntConv `Int64'+ , cFromEnum `CopyDirection' } -> `Status' cToEnum #}+++-- |+-- Copy data between the host and device asynchronously, possibly associated+-- with a particular stream. The host-side memory must be page-locked (allocated+-- with 'mallocHostArray').+--+{-# INLINEABLE memcpyAsync #-}+memcpyAsync :: Storable a+ => Ptr a -- ^ destination+ -> Ptr a -- ^ source+ -> Int -- ^ number of elements+ -> CopyDirection+ -> Maybe Stream+ -> IO ()+memcpyAsync !dst !src !n !kind !mst = doMemcpy undefined dst+ where+ doMemcpy :: Storable a' => a' -> Ptr a' -> IO ()+ doMemcpy x _ =+ let bytes = fromIntegral n * fromIntegral (sizeOf x) in+ nothingIfOk =<< cudaMemcpyAsync dst src bytes kind (fromMaybe defaultStream mst)++{-# INLINE cudaMemcpyAsync #-}+{# fun cudaMemcpyAsync+ { castPtr `Ptr a'+ , castPtr `Ptr a'+ , cIntConv `Int64'+ , cFromEnum `CopyDirection'+ , useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Copy a 2D memory area between the host and device. This is a synchronous+-- operation.+--+{-# INLINEABLE memcpy2D #-}+memcpy2D :: Storable a+ => Ptr a -- ^ destination+ -> Int -- ^ width of destination array+ -> Ptr a -- ^ source+ -> Int -- ^ width of source array+ -> Int -- ^ width to copy+ -> Int -- ^ height to copy+ -> CopyDirection+ -> IO ()+memcpy2D !dst !dw !src !sw !w !h !kind = doCopy undefined dst+ where+ doCopy :: Storable a' => a' -> Ptr a' -> IO ()+ doCopy x _ =+ let bytes = fromIntegral (sizeOf x)+ dw' = fromIntegral dw * bytes+ sw' = fromIntegral sw * bytes+ w' = fromIntegral w * bytes+ h' = fromIntegral h+ in+ nothingIfOk =<< cudaMemcpy2D dst dw' src sw' w' h' kind++{-# INLINE cudaMemcpy2D #-}+{# fun cudaMemcpy2D+ { castPtr `Ptr a'+ , `Int64'+ , castPtr `Ptr a'+ , `Int64'+ , `Int64'+ , `Int64'+ , cFromEnum `CopyDirection'+ }+ -> `Status' cToEnum #}+++-- |+-- Copy a 2D memory area between the host and device asynchronously, possibly+-- associated with a particular stream. The host-side memory must be+-- page-locked.+--+{-# INLINEABLE memcpy2DAsync #-}+memcpy2DAsync :: Storable a+ => Ptr a -- ^ destination+ -> Int -- ^ width of destination array+ -> Ptr a -- ^ source+ -> Int -- ^ width of source array+ -> Int -- ^ width to copy+ -> Int -- ^ height to copy+ -> CopyDirection+ -> Maybe Stream+ -> IO ()+memcpy2DAsync !dst !dw !src !sw !w !h !kind !mst = doCopy undefined dst+ where+ doCopy :: Storable a' => a' -> Ptr a' -> IO ()+ doCopy x _ =+ let bytes = fromIntegral (sizeOf x)+ dw' = fromIntegral dw * bytes+ sw' = fromIntegral sw * bytes+ w' = fromIntegral w * bytes+ h' = fromIntegral h+ st = fromMaybe defaultStream mst+ in+ nothingIfOk =<< cudaMemcpy2DAsync dst dw' src sw' w' h' kind st++{-# INLINE cudaMemcpy2DAsync #-}+{# fun cudaMemcpy2DAsync+ { castPtr `Ptr a'+ , `Int64'+ , castPtr `Ptr a'+ , `Int64'+ , `Int64'+ , `Int64'+ , cFromEnum `CopyDirection'+ , useStream `Stream'+ }+ -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Combined Allocation and Marshalling+--------------------------------------------------------------------------------++-- |+-- Write a list of storable elements into a newly allocated device array,+-- returning the device pointer together with the number of elements that were+-- written. Note that this requires two copy operations: firstly from a Haskell+-- list into a heap-allocated array, and from there into device memory. The+-- array should be 'free'd when no longer required.+--+{-# INLINEABLE newListArrayLen #-}+newListArrayLen :: Storable a => [a] -> IO (DevicePtr a, Int)+newListArrayLen !xs =+ F.withArrayLen xs $ \len p ->+ bracketOnError (mallocArray len) free $ \d_xs -> do+ pokeArray len p d_xs+ return (d_xs, len)+++-- |+-- Write a list of storable elements into a newly allocated device array. This+-- is 'newListArrayLen' composed with 'fst'.+--+{-# INLINEABLE newListArray #-}+newListArray :: Storable a => [a] -> IO (DevicePtr a)+newListArray !xs = fst `fmap` newListArrayLen xs+++-- |+-- Temporarily store a list of elements into a newly allocated device array. An+-- IO action is applied to the array, the result of which is returned. Similar+-- to 'newListArray', this requires two marshalling operations of the data.+--+-- As with 'allocaArray', the memory is freed once the action completes, so you+-- should not return the pointer from the action, and be sure that any+-- asynchronous operations (such as kernel execution) have completed.+--+{-# INLINEABLE withListArray #-}+withListArray :: Storable a => [a] -> (DevicePtr a -> IO b) -> IO b+withListArray !xs = withListArrayLen xs . const+++-- |+-- A variant of 'withListArray' which also supplies the number of elements in+-- the array to the applied function+--+{-# INLINEABLE withListArrayLen #-}+withListArrayLen :: Storable a => [a] -> (Int -> DevicePtr a -> IO b) -> IO b+withListArrayLen !xs !f =+ bracket (newListArrayLen xs) (free . fst) (uncurry . flip $ f)+--+-- XXX: Will this attempt to double-free the device array on error (together+-- with newListArrayLen)?+--+++--------------------------------------------------------------------------------+-- Utility+--------------------------------------------------------------------------------++-- |+-- Initialise device memory to a given 8-bit value+--+{-# INLINEABLE memset #-}+memset :: DevicePtr a -- ^ The device memory+ -> Int64 -- ^ Number of bytes+ -> Int8 -- ^ Value to set for each byte+ -> IO ()+memset !dptr !bytes !symbol = nothingIfOk =<< cudaMemset dptr symbol bytes++{-# INLINE cudaMemset #-}+{# fun unsafe cudaMemset+ { dptr `DevicePtr a'+ , cIntConv `Int8'+ , cIntConv `Int64' } -> `Status' cToEnum #}+ where+ dptr = useDevicePtr . castDevPtr+
+ src/Foreign/CUDA/Runtime/Stream.chs view
@@ -0,0 +1,115 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Stream+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Stream management routines+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Stream (++ -- * Stream Management+ Stream(..),+ create, destroy, finished, block, defaultStream++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Types+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+import Control.Monad ( liftM )+import Control.Exception ( throwIO )+++--------------------------------------------------------------------------------+-- Functions+--------------------------------------------------------------------------------++-- |+-- Create a new asynchronous stream+--+{-# INLINEABLE create #-}+create :: IO Stream+create = resultIfOk =<< cudaStreamCreate++{-# INLINE cudaStreamCreate #-}+{# fun unsafe cudaStreamCreate+ { alloca- `Stream' peekStream* } -> `Status' cToEnum #}+++-- |+-- Destroy and clean up an asynchronous stream+--+{-# INLINEABLE destroy #-}+destroy :: Stream -> IO ()+destroy !s = nothingIfOk =<< cudaStreamDestroy s++{-# INLINE cudaStreamDestroy #-}+{# fun unsafe cudaStreamDestroy+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Determine if all operations in a stream have completed+--+{-# INLINEABLE finished #-}+finished :: Stream -> IO Bool+finished !s =+ cudaStreamQuery s >>= \rv -> do+ case rv of+ Success -> return True+ NotReady -> return False+ _ -> throwIO (ExitCode rv)++{-# INLINE cudaStreamQuery #-}+{# fun unsafe cudaStreamQuery+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- Block until all operations in a Stream have been completed+--+{-# INLINEABLE block #-}+block :: Stream -> IO ()+block !s = nothingIfOk =<< cudaStreamSynchronize s++{-# INLINE cudaStreamSynchronize #-}+{# fun cudaStreamSynchronize+ { useStream `Stream' } -> `Status' cToEnum #}+++-- |+-- The main execution stream (0)+--+-- {-# INLINE defaultStream #-}+-- defaultStream :: Stream+-- #if CUDART_VERSION < 3010+-- defaultStream = Stream 0+-- #else+-- defaultStream = Stream nullPtr+-- #endif++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++{-# INLINE peekStream #-}+peekStream :: Ptr {#type cudaStream_t#} -> IO Stream+#if CUDART_VERSION < 3010+peekStream = liftM Stream . peekIntConv+#else+peekStream = liftM Stream . peek+#endif+
+ src/Foreign/CUDA/Runtime/Texture.chs view
@@ -0,0 +1,203 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Texture+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Texture references+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Texture (++ -- * Texture Reference Management+ Texture(..), FormatKind(..), AddressMode(..), FilterMode(..), FormatDesc(..),+ bind, bind2D++) where++-- Friends+import Foreign.CUDA.Ptr+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Data.Int+import Foreign+import Foreign.C++#include "cbits/stubs.h"+{# context lib="cudart" #}++#c+typedef struct textureReference textureReference;+typedef struct cudaChannelFormatDesc cudaChannelFormatDesc;+#endc++--------------------------------------------------------------------------------+-- Data Types+--------------------------------------------------------------------------------++-- |A texture reference+--+{# pointer *textureReference as ^ -> Texture #}++data Texture = Texture+ {+ normalised :: !Bool, -- ^ access texture using normalised coordinates [0.0,1.0)+ filtering :: !FilterMode,+ addressing :: !(AddressMode, AddressMode, AddressMode),+ format :: !FormatDesc+ }+ deriving (Eq, Show)++-- |Texture channel format kind+--+{# enum cudaChannelFormatKind as FormatKind+ { }+ with prefix="cudaChannelFormatKind" deriving (Eq, Show) #}++-- |Texture addressing mode+--+{# enum cudaTextureAddressMode as AddressMode+ { }+ with prefix="cudaAddressMode" deriving (Eq, Show) #}++-- |Texture filtering mode+--+{# enum cudaTextureFilterMode as FilterMode+ { }+ with prefix="cudaFilterMode" deriving (Eq, Show) #}+++-- |A description of how memory read through the texture cache should be+-- interpreted, including the kind of data and the number of bits of each+-- component (x,y,z and w, respectively).+--+{# pointer *cudaChannelFormatDesc as ^ foreign -> FormatDesc nocode #}++data FormatDesc = FormatDesc+ {+ depth :: !(Int,Int,Int,Int),+ kind :: !FormatKind+ }+ deriving (Eq, Show)++instance Storable FormatDesc where+ sizeOf _ = {# sizeof cudaChannelFormatDesc #}+ alignment _ = alignment (undefined :: Ptr ())++ peek p = do+ dx <- cIntConv `fmap` {# get cudaChannelFormatDesc.x #} p+ dy <- cIntConv `fmap` {# get cudaChannelFormatDesc.y #} p+ dz <- cIntConv `fmap` {# get cudaChannelFormatDesc.z #} p+ dw <- cIntConv `fmap` {# get cudaChannelFormatDesc.w #} p+ df <- cToEnum `fmap` {# get cudaChannelFormatDesc.f #} p+ return $ FormatDesc (dx,dy,dz,dw) df++ poke p (FormatDesc (x,y,z,w) k) = do+ {# set cudaChannelFormatDesc.x #} p (cIntConv x)+ {# set cudaChannelFormatDesc.y #} p (cIntConv y)+ {# set cudaChannelFormatDesc.z #} p (cIntConv z)+ {# set cudaChannelFormatDesc.w #} p (cIntConv w)+ {# set cudaChannelFormatDesc.f #} p (cFromEnum k)+++instance Storable Texture where+ sizeOf _ = {# sizeof textureReference #}+ alignment _ = alignment (undefined :: Ptr ())++ peek p = do+ norm <- cToBool `fmap` {# get textureReference.normalized #} p+ fmt <- cToEnum `fmap` {# get textureReference.filterMode #} p+ dsc <- peek . castPtr =<< {# get textureReference.channelDesc #} p+ [x,y,z] <- peekArrayWith cToEnum 3 =<< {# get textureReference.addressMode #} p+ return $ Texture norm fmt (x,y,z) dsc++ poke p (Texture norm fmt (x,y,z) dsc) = do+ {# set textureReference.normalized #} p (cFromBool norm)+ {# set textureReference.filterMode #} p (cFromEnum fmt)+ withArray (map cFromEnum [x,y,z]) ({# set textureReference.addressMode #} p)++ -- c2hs is returning the wrong type for structs-within-structs+ dscptr <- {# get textureReference.channelDesc #} p+ poke (castPtr dscptr) dsc+++--------------------------------------------------------------------------------+-- Texture References+--------------------------------------------------------------------------------++-- |Bind the memory area associated with the device pointer to a texture+-- reference given by the named symbol. Any previously bound references are+-- unbound.+--+{-# INLINEABLE bind #-}+bind :: String -> Texture -> DevicePtr a -> Int64 -> IO ()+bind !name !tex !dptr !bytes = do+ ref <- getTex name+ poke ref tex+ nothingIfOk =<< cudaBindTexture ref dptr (format tex) bytes++{-# INLINE cudaBindTexture #-}+{# fun unsafe cudaBindTexture+ { alloca- `Int'+ , id `TextureReference'+ , dptr `DevicePtr a'+ , with_* `FormatDesc'+ , `Int64' } -> `Status' cToEnum #}+ where dptr = useDevicePtr . castDevPtr++-- |Bind the two-dimensional memory area to the texture reference associated+-- with the given symbol. The size of the area is constrained by (width,height)+-- in texel units, and the row pitch in bytes. Any previously bound references+-- are unbound.+--+{-# INLINEABLE bind2D #-}+bind2D :: String -> Texture -> DevicePtr a -> (Int,Int) -> Int64 -> IO ()+bind2D !name !tex !dptr (!width,!height) !bytes = do+ ref <- getTex name+ poke ref tex+ nothingIfOk =<< cudaBindTexture2D ref dptr (format tex) width height bytes++{-# INLINE cudaBindTexture2D #-}+{# fun unsafe cudaBindTexture2D+ { alloca- `Int'+ , id `TextureReference'+ , dptr `DevicePtr a'+ , with_* `FormatDesc'+ , `Int'+ , `Int'+ , `Int64' } -> `Status' cToEnum #}+ where dptr = useDevicePtr . castDevPtr+++-- |Returns the texture reference associated with the given symbol+--+{-# INLINEABLE getTex #-}+getTex :: String -> IO TextureReference+getTex !name = resultIfOk =<< cudaGetTextureReference name++{-# INLINE cudaGetTextureReference #-}+{# fun unsafe cudaGetTextureReference+ { alloca- `Ptr Texture' peek*+ , withCString_* `String' } -> `Status' cToEnum #}+++--------------------------------------------------------------------------------+-- Internal+--------------------------------------------------------------------------------++{-# INLINE with_ #-}+with_ :: Storable a => a -> (Ptr a -> IO b) -> IO b+with_ = with+++-- CUDA 5.0 changed the types of some attributes from char* to void*+--+{-# INLINE withCString_ #-}+withCString_ :: String -> (Ptr a -> IO b) -> IO b+withCString_ !str !fn = withCString str (fn . castPtr)+
+ src/Foreign/CUDA/Runtime/Utils.chs view
@@ -0,0 +1,53 @@+{-# LANGUAGE ForeignFunctionInterface #-}+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Runtime.Utils+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Utility functions+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Runtime.Utils (++ runtimeVersion,+ driverVersion,++) where++#include "cbits/stubs.h"+{# context lib="cudart" #}++-- Friends+import Foreign.CUDA.Runtime.Error+import Foreign.CUDA.Internal.C2HS++-- System+import Foreign+import Foreign.C+++-- |+-- Return the version number of the installed CUDA driver+--+{-# INLINEABLE runtimeVersion #-}+runtimeVersion :: IO Int+runtimeVersion = resultIfOk =<< cudaRuntimeGetVersion++{-# INLINE cudaRuntimeGetVersion #-}+{# fun unsafe cudaRuntimeGetVersion+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+++-- |+-- Return the version number of the installed CUDA runtime+--+{-# INLINEABLE driverVersion #-}+driverVersion :: IO Int+driverVersion = resultIfOk =<< cudaDriverGetVersion++{-# INLINE cudaDriverGetVersion #-}+{# fun unsafe cudaDriverGetVersion+ { alloca- `Int' peekIntConv* } -> `Status' cToEnum #}+
+ src/Foreign/CUDA/Types.chs view
@@ -0,0 +1,155 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-}+#ifdef USE_EMPTY_CASE+{-# LANGUAGE EmptyCase #-}+#endif+--------------------------------------------------------------------------------+-- |+-- Module : Foreign.CUDA.Types+-- Copyright : [2009..2014] Trevor L. McDonell+-- License : BSD+--+-- Data types that are equivalent and can be shared freely between the CUDA+-- Runtime and Driver APIs.+--+--------------------------------------------------------------------------------++module Foreign.CUDA.Types (++ -- * Pointers+ DevicePtr(..), HostPtr(..),++ -- * Events+ Event(..), EventFlag(..), WaitFlag,++ -- * Streams+ Stream(..), StreamPriority, StreamFlag,+ defaultStream,++) where++-- system+import Foreign.Ptr+import Foreign.Storable++#include "cbits/stubs.h"+{# context lib="cuda" #}+++--------------------------------------------------------------------------------+-- Data pointers+--------------------------------------------------------------------------------++-- |+-- A reference to data stored on the device.+--+newtype DevicePtr a = DevicePtr { useDevicePtr :: Ptr a }+ deriving (Eq,Ord)++instance Show (DevicePtr a) where+ showsPrec n (DevicePtr p) = showsPrec n p++instance Storable (DevicePtr a) where+ sizeOf _ = sizeOf (undefined :: Ptr a)+ alignment _ = alignment (undefined :: Ptr a)+ peek p = DevicePtr `fmap` peek (castPtr p)+ poke p v = poke (castPtr p) (useDevicePtr v)+++-- |+-- A reference to page-locked host memory.+--+-- A 'HostPtr' is just a plain 'Ptr', but the memory has been allocated by CUDA+-- into page locked memory. This means that the data can be copied to the GPU+-- via DMA (direct memory access). Note that the use of the system function+-- `mlock` is not sufficient here --- the CUDA version ensures that the+-- /physical/ address stays this same, not just the virtual address.+--+-- To copy data into a 'HostPtr' array, you may use for example 'withHostPtr'+-- together with 'Foreign.Marshal.Array.copyArray' or+-- 'Foreign.Marshal.Array.moveArray'.+--+newtype HostPtr a = HostPtr { useHostPtr :: Ptr a }+ deriving (Eq,Ord)++instance Show (HostPtr a) where+ showsPrec n (HostPtr p) = showsPrec n p++instance Storable (HostPtr a) where+ sizeOf _ = sizeOf (undefined :: Ptr a)+ alignment _ = alignment (undefined :: Ptr a)+ peek p = HostPtr `fmap` peek (castPtr p)+ poke p v = poke (castPtr p) (useHostPtr v)+++--------------------------------------------------------------------------------+-- Events+--------------------------------------------------------------------------------++-- |+-- Events are markers that can be inserted into the CUDA execution stream and+-- later queried.+--+newtype Event = Event { useEvent :: {# type CUevent #}}+ deriving (Eq, Show)++-- |+-- Event creation flags+--+{# enum CUevent_flags as EventFlag+ { underscoreToCase }+ with prefix="CU_EVENT" deriving (Eq, Show, Bounded) #}++-- |+-- Possible option flags for waiting for events+--+data WaitFlag+instance Enum WaitFlag where+#ifdef USE_EMPTY_CASE+ toEnum x = case x of {}+ fromEnum x = case x of {}+#endif+++--------------------------------------------------------------------------------+-- Stream management+--------------------------------------------------------------------------------++-- |+-- A processing stream. All operations in a stream are synchronous and executed+-- in sequence, but operations in different non-default streams may happen+-- out-of-order or concurrently with one another.+--+-- Use 'Event's to synchronise operations between streams.+--+newtype Stream = Stream { useStream :: {# type CUstream #}}+ deriving (Eq, Show)+++-- |+-- Priority of an execution stream. Work submitted to a higher priority+-- stream may preempt execution of work already executing in a lower+-- priority stream. Lower numbers represent higher priorities.+--+type StreamPriority = Int++-- |+-- Possible option flags for stream initialisation. Dummy instance until the API+-- exports actual option values.+--+data StreamFlag+instance Enum StreamFlag where+#ifdef USE_EMPTY_CASE+ toEnum x = case x of {}+ fromEnum x = case x of {}+#endif++-- |+-- The main execution stream. No operations overlap with operations in the+-- default stream.+--+{-# INLINE defaultStream #-}+defaultStream :: Stream+defaultStream = Stream nullPtr+
+ src/Text/Show/Describe.hs view
@@ -0,0 +1,18 @@+--------------------------------------------------------------------------------+-- |+-- Module : Text.Show.Describe+-- Copyright : [2016] Trevor L. McDonell+-- License : BSD+--+--------------------------------------------------------------------------------++module Text.Show.Describe+ where+++-- | Like 'Text.Show.Show', but focuses on providing a more detailed description+-- of the value rather than a 'Text.Read.read'able representation.+--+class Describe a where+ describe :: a -> String+