#define _REENTRANT

#include <cuda.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

#include "ezt_cuda.h"
#include "eztrace.h"

extern "C" {

  static unsigned kernel_id = 0;

  /* Kernel management */
  CUresult cuLaunchKernel(CUfunction f,
			  unsigned int gridDimX,
			  unsigned int gridDimY,
			  unsigned int gridDimZ,
			  unsigned int blockDimX,
			  unsigned int blockDimY,
			  unsigned int blockDimZ,
			  unsigned int sharedMemBytes,
			  CUstream hStream,
			  void **kernelParams,
			  void **extra) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    unsigned current_id = kernel_id++;
    // TODO: distinguish between runtime and driver API

    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_START, deviceId, current_id);

    res = libcuLaunchKernel(f, gridDimX, gridDimY, gridDimZ, blockDimX, blockDimY, blockDimZ,
				     sharedMemBytes, hStream, kernelParams, extra);
    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_STOP, deviceId, current_id);
    return res;
  }

  CUresult  cuLaunch(CUfunction f) { // deprecated
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    unsigned current_id = kernel_id++;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_START, deviceId, current_id);
    res = libcuLaunch(f);
    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_STOP, deviceId, current_id);
    return res;    
  }

  CUresult  cuLaunchGrid(CUfunction f, int grid_width, int grid_height) { // deprecated
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    unsigned current_id = kernel_id++;

    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_START, deviceId, current_id);
    res = libcuLaunchGrid(f, grid_width, grid_height);
    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_STOP, deviceId, current_id);
    return res;    
  }

  CUresult  cuLaunchGridAsync(CUfunction f, int grid_width, int grid_height, CUstream hStream) { // deprecated
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    unsigned current_id = kernel_id++;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_START, deviceId, current_id);
    res = libcuLaunchGridAsync(f, grid_width, grid_height, hStream);
    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CULAUNCHKERNEL_STOP, deviceId, current_id);
    return res;    
  }

  /* Memory Management */

  CUresult cuMemAlloc_v2(CUdeviceptr *dptr, size_t bytesize) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = bytesize;

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CUMEMALLOC_START, deviceId, size);
    res = libcuMemAlloc_v2(dptr, bytesize);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMALLOC_STOP, deviceId, size, (app_ptr)*dptr);
    return res;
  }

  CUresult  cuMemAllocPitch_v2(CUdeviceptr *dptr, size_t *pPitch, size_t WidthInBytes, size_t Height, unsigned int ElementSizeBytes)  {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    ezt_cuda_size_t size = Height * WidthInBytes;

    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CUMEMALLOC_START, deviceId, size);
    res = libcuMemAllocPitch_v2(dptr, pPitch, WidthInBytes, Height, ElementSizeBytes);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMALLOC_STOP, deviceId, size, *dptr);
    return res;
  }

  CUresult cuMemFree_v2(CUdeviceptr dptr) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;

    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CUDAFREE_START, deviceId, dptr);
    res = libcuMemFree_v2(dptr);
    EZTRACE_EVENT_PACKED_2(EZTRACE_CUDA_CUDAFREE_STOP, deviceId, dptr);
    return res;
  }



  /* Memory Transfers */

  CUresult cuMemcpy(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, 0);
    res = libcuMemcpy(dst, src, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, 0);
    return res;
  }

  CUresult cuMemcpyAsync(CUdeviceptr dst, CUdeviceptr src, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, 0);
    res = libcuMemcpyAsync(dst, src, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, 0);
    return res;
  }

  CUresult cuMemcpyAtoA_v2(CUarray dstArray,
			   size_t dstOffset,
			   CUarray srcArray,
			   size_t srcOffset,
			   size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_ATOA;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyAtoA_v2(dstArray, dstOffset, srcArray, srcOffset, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyAtoD_v2(CUdeviceptr dstDevice, CUarray srcArray, size_t srcOffset, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_ATOD;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyAtoD_v2(dstDevice, srcArray, srcOffset, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyAtoH_v2(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_ATOH;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyAtoH_v2(dstHost, srcArray, srcOffset, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyAtoHAsync_v2(void *dstHost, CUarray srcArray, size_t srcOffset, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_ATOH;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyAtoHAsync_v2(dstHost, srcArray, srcOffset, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyDtoA_v2(CUarray dstArray, size_t dstOffset, CUdeviceptr srcDevice, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_DTOA;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyDtoA_v2(dstArray, dstOffset, srcDevice, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyDtoD_v2(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_DTOD;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyDtoD_v2( dstDevice, srcDevice, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyDtoDAsync_v2(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_DTOD;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyDtoDAsync_v2( dstDevice, srcDevice, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyDtoH_v2(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_DTOH;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyDtoH_v2(dstHost, srcDevice, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyDtoHAsync_v2(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_DTOH;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyDtoHAsync_v2(dstHost, srcDevice, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyHtoA_v2(CUarray dstArray, size_t dstOffset, const void* srcHost, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_HTOA;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyHtoA_v2( dstArray, dstOffset, srcHost, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyHtoAAsync_v2(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_HTOA;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyHtoAAsync_v2( dstArray, dstOffset, srcHost, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyHtoD_v2(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_HTOD;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyHtoD_v2( dstDevice, srcHost, ByteCount);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpyHtoDAsync_v2(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = CUDA_MEMCPY_KIND_HTOD;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);
    ezt_cuda_size_t size = ByteCount;

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpyHtoDAsync_v2( dstDevice, srcHost, ByteCount, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpy2D_v2(const CUDA_MEMCPY2D *pCopy) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = memoryTypesToCpyKind(pCopy->srcMemoryType, pCopy->dstMemoryType);
    ezt_cuda_size_t size = pCopy->WidthInBytes * pCopy->Height;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpy2D_v2(pCopy);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpy2DUnaligned_v2(const CUDA_MEMCPY2D *pCopy) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = memoryTypesToCpyKind(pCopy->srcMemoryType, pCopy->dstMemoryType);
    ezt_cuda_size_t size = pCopy->WidthInBytes * pCopy->Height;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpy2DUnaligned_v2(pCopy);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpy2DAsync_v2(const CUDA_MEMCPY2D *pCopy, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = memoryTypesToCpyKind(pCopy->srcMemoryType, pCopy->dstMemoryType);
    ezt_cuda_size_t size = pCopy->WidthInBytes * pCopy->Height;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpy2DAsync_v2(pCopy, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpy3D_v2(const CUDA_MEMCPY3D *pCopy) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = memoryTypesToCpyKind(pCopy->srcMemoryType, pCopy->dstMemoryType);
    ezt_cuda_size_t size = pCopy->WidthInBytes * pCopy->Height * pCopy->Depth;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpy3D_v2(pCopy);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }

  CUresult cuMemcpy3DAsync_v2(const CUDA_MEMCPY3D *pCopy, CUstream hStream) {
    FUNCTION_ENTRY;
    EZT_CUDA_INITIALIZE;
    enum ezt_cudaMemcpyKind kind = memoryTypesToCpyKind(pCopy->srcMemoryType, pCopy->dstMemoryType);
    ezt_cuda_size_t size = pCopy->WidthInBytes * pCopy->Height * pCopy->Depth;
    CUdevice deviceId;
    CUresult res = cuCtxGetDevice(&deviceId);
    assert(res == CUDA_SUCCESS);

    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_START, deviceId, size, kind);
    res = libcuMemcpy3DAsync_v2(pCopy, hStream);
    EZTRACE_EVENT_PACKED_3(EZTRACE_CUDA_CUMEMCPY_STOP, deviceId, size, kind);
    return res;
  }


  // to be implemented

  CUresult  cuMemGetInfo_v2(size_t *free, size_t *total) {
    return libcuMemGetInfo_v2(free, total);
  }

  CUresult cuMemAllocHost_v2(void **pp, size_t bytesize) {
    return libcuMemAllocHost_v2(pp, bytesize);
  }

  CUresult cuMemFreeHost(void *p) {
    return libcuMemFreeHost(p);
  }

  CUresult cuMemHostAlloc(void **pp, size_t bytesize, unsigned int Flags) {
    return libcuMemHostAlloc(pp, bytesize, Flags);
  }

  CUresult cuMemHostRegister(void *p, size_t bytesize, unsigned int Flags) {
    return libcuMemHostRegister(p, bytesize, Flags);
  }

  CUresult cuMemHostUnregister(void *p) {
    return libcuMemHostUnregister(p);
  }


  CUresult cuMemcpyPeer(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount) {
    return libcuMemcpyPeer(dstDevice, dstContext, srcDevice, srcContext,  ByteCount);
  }

  CUresult cuMemcpyPeerAsync(CUdeviceptr dstDevice, CUcontext dstContext, CUdeviceptr srcDevice, CUcontext srcContext, size_t ByteCount, CUstream hStream) {
    return libcuMemcpyPeerAsync(dstDevice, dstContext, srcDevice, srcContext, ByteCount, hStream);
  }

  CUresult cuMemcpy3DPeer(const CUDA_MEMCPY3D_PEER *pCopy) {
    return libcuMemcpy3DPeer(pCopy);
  }

  CUresult cuMemcpy3DPeerAsync(const CUDA_MEMCPY3D_PEER *pCopy, CUstream hStream) {
    return libcuMemcpy3DPeerAsync(pCopy, hStream);
  }

  CUresult cuMemsetD8_v2(CUdeviceptr dstDevice, unsigned char uc, size_t N) {
    return libcuMemsetD8_v2(dstDevice, uc, N);
  }

  CUresult cuMemsetD16_v2(CUdeviceptr dstDevice, unsigned short us, size_t N) {
    return libcuMemsetD16_v2(dstDevice, us, N);
  }

  CUresult cuMemsetD32_v2(CUdeviceptr dstDevice, unsigned int ui, size_t N) {
    return libcuMemsetD32_v2(dstDevice, ui, N);
  }

  CUresult cuMemsetD2D8_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height) {
    return libcuMemsetD2D8_v2(dstDevice, dstPitch, uc, Width, Height);
  }

  CUresult cuMemsetD2D16_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height) {
    return libcuMemsetD2D16_v2(dstDevice, dstPitch, us, Width, Height);
  }

  CUresult cuMemsetD2D32_v2(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height) {
    return libcuMemsetD2D32_v2(dstDevice, dstPitch, ui, Width, Height);
  }
    
  CUresult cuMemsetD8Async(CUdeviceptr dstDevice, unsigned char uc, size_t N, CUstream hStream) {
    return libcuMemsetD8Async(dstDevice, uc, N, hStream);
  }

  CUresult cuMemsetD16Async(CUdeviceptr dstDevice, unsigned short us, size_t N, CUstream hStream) {
    return libcuMemsetD16Async(dstDevice, us, N, hStream);
  }

  CUresult cuMemsetD32Async(CUdeviceptr dstDevice, unsigned int ui, size_t N, CUstream hStream) {
    return libcuMemsetD32Async(dstDevice, ui, N, hStream);
  }
  CUresult cuMemsetD2D8Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned char uc, size_t Width, size_t Height, CUstream hStream) {
    return libcuMemsetD2D8Async(dstDevice, dstPitch, uc, Width, Height, hStream);
  }
  CUresult cuMemsetD2D16Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned short us, size_t Width, size_t Height, CUstream hStream) {
    return libcuMemsetD2D16Async(dstDevice, dstPitch, us, Width, Height, hStream);
  }
  CUresult cuMemsetD2D32Async(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height, CUstream hStream) {
    return libcuMemsetD2D32Async(dstDevice, dstPitch, ui, Width, Height, hStream);
  }

#if 0
  /* is it useful ? */
  CUresult  cuArrayCreate(CUarray *pHandle, const CUDA_ARRAY_DESCRIPTOR *pAllocateArray) {
    return libcuArrayCreate(pHandle, pAllocateArray);
  }
  CUresult cuArrayGetDescriptor(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray) {
    return libcuArrayGetDescriptor(pArrayDescriptor, hArray);
  }
  CUresult cuArrayDestroy(CUarray hArray) {
    return libcuArrayDestroy(hArray);
  }
  CUresult cuArray3DCreate(CUarray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pAllocateArray) {
    return libcuArray3DCreate(pHandle, pAllocateArray);
  }
  CUresult cuArray3DGetDescriptor(CUDA_ARRAY3D_DESCRIPTOR *pArrayDescriptor, CUarray hArray) {
    return libcuArray3DGetDescriptor(pArrayDescriptor, hArray);
  }
  CUresult cuMipmappedArrayCreate(CUmipmappedArray *pHandle, const CUDA_ARRAY3D_DESCRIPTOR *pMipmappedArrayDesc, unsigned int numMipmapLevels) {
    return libcuMipmappedArrayCreate(pHandle, pMipmappedArrayDesc, numMipmapLevels);
  }
  CUresult cuMipmappedArrayGetLevel(CUarray *pLevelArray, CUmipmappedArray hMipmappedArray, unsigned int level) {
    return libcuMipmappedArrayGetLevel(pLevelArray, hMipmappedArray, level);
  }
  CUresult cuMipmappedArrayDestroy(CUmipmappedArray hMipmappedArray) {
    return libcuMipmappedArrayDestroy(hMipmappedArray);
  }
#endif

}



