#ifndef __CUDA_EV_CODES_H__
#define __CUDA_EV_CODES_H__

#include <stdint.h>
#include "ev_codes.h"


#define EZTRACE_CUDA_EVENTS_ID 0x07
#define EZTRACE_CUDA_PREFIX    (EZTRACE_CUDA_EVENTS_ID << NB_BITS_EVENTS)


#define EZTRACE_CUDA_CUMEMALLOC_START            (EZTRACE_CUDA_PREFIX | 0X0110)
#define EZTRACE_CUDA_CUMEMALLOC_STOP             (EZTRACE_CUDA_PREFIX | 0X0111)
#define EZTRACE_CUDA_CUDAFREE_START              (EZTRACE_CUDA_PREFIX | 0X0112)
#define EZTRACE_CUDA_CUDAFREE_STOP               (EZTRACE_CUDA_PREFIX | 0X0113)
#define EZTRACE_CUDA_CULAUNCHKERNEL_START        (EZTRACE_CUDA_PREFIX | 0X0120)
#define EZTRACE_CUDA_CULAUNCHKERNEL_STOP         (EZTRACE_CUDA_PREFIX | 0X0121)
#define EZTRACE_CUDA_CUDATHREADSYNCHRONIZE_START (EZTRACE_CUDA_PREFIX | 0X0130)
#define EZTRACE_CUDA_CUDATHREADSYNCHRONIZE_STOP  (EZTRACE_CUDA_PREFIX | 0X0131)
#define EZTRACE_CUDA_CUINIT                      (EZTRACE_CUDA_PREFIX | 0X0140)
#define EZTRACE_CUDA_SETNBDEVICES                (EZTRACE_CUDA_PREFIX | 0X0141)
#define EZTRACE_CUDA_CUMEMCPY_START              (EZTRACE_CUDA_PREFIX | 0X0150)
#define EZTRACE_CUDA_CUMEMCPY_STOP               (EZTRACE_CUDA_PREFIX | 0X0151)

#define EZTRACE_CUDA_CUDADEVICESYNCHRONIZE_START (EZTRACE_CUDA_PREFIX | 0X0160)
#define EZTRACE_CUDA_CUDADEVICESYNCHRONIZE_STOP  (EZTRACE_CUDA_PREFIX | 0X0161)

#define EZTRACE_CUDA_GPU_KERNEL_TIMESTAMPS       (EZTRACE_CUDA_PREFIX | 0X0210)
#define EZTRACE_CUDA_GPU_MEMCPY_TIMESTAMPS       (EZTRACE_CUDA_PREFIX | 0X0211)

#define EZTRACE_CUDA_REGISTER_KERNEL             (EZTRACE_CUDA_PREFIX | 0X1001)
#define EZTRACE_CUDA_KERNEL_NAME                 (EZTRACE_CUDA_PREFIX | 0X1002)

typedef uint32_t kernel_id_t;
typedef uint64_t ezt_cuda_size_t;


enum ezt_cudaMemcpyKind {
  CUDA_MEMCPY_KIND_HTOD = 1,
  CUDA_MEMCPY_KIND_DTOH = 2,
  CUDA_MEMCPY_KIND_HTOA = 3,
  CUDA_MEMCPY_KIND_ATOH = 4,
  CUDA_MEMCPY_KIND_ATOA = 5,
  CUDA_MEMCPY_KIND_ATOD = 6,
  CUDA_MEMCPY_KIND_DTOA = 7,
  CUDA_MEMCPY_KIND_DTOD = 8,
  CUDA_MEMCPY_KIND_HTOH = 9,
  CUDA_MEMCPY_KIND_UNKNOWN = -1
};

#define memoryTypesToCpyKind(srcType, destType)				\
  (((srcType)== CU_MEMORYTYPE_HOST && (destType)== CU_MEMORYTYPE_HOST)? CUDA_MEMCPY_KIND_HTOH : \
   ((srcType)== CU_MEMORYTYPE_HOST && (destType)== CU_MEMORYTYPE_DEVICE)? CUDA_MEMCPY_KIND_HTOD : \
   ((srcType)== CU_MEMORYTYPE_HOST && (destType)== CU_MEMORYTYPE_ARRAY)? CUDA_MEMCPY_KIND_HTOA : \
   ((srcType)== CU_MEMORYTYPE_DEVICE && (destType)== CU_MEMORYTYPE_HOST)? CUDA_MEMCPY_KIND_DTOH : \
   ((srcType)== CU_MEMORYTYPE_DEVICE && (destType)== CU_MEMORYTYPE_DEVICE)? CUDA_MEMCPY_KIND_DTOD : \
   ((srcType)== CU_MEMORYTYPE_DEVICE && (destType)== CU_MEMORYTYPE_ARRAY)? CUDA_MEMCPY_KIND_DTOA : \
   ((srcType)== CU_MEMORYTYPE_ARRAY && (destType)== CU_MEMORYTYPE_HOST)? CUDA_MEMCPY_KIND_ATOH : \
   ((srcType)== CU_MEMORYTYPE_ARRAY && (destType)== CU_MEMORYTYPE_DEVICE)? CUDA_MEMCPY_KIND_ATOD : \
   ((srcType)== CU_MEMORYTYPE_ARRAY && (destType)== CU_MEMORYTYPE_ARRAY)? CUDA_MEMCPY_KIND_ATOA : \
   CUDA_MEMCPY_KIND_UNKNOWN)

#define CUDA_MEMCPY_KIND_TO_EZT(kind)					\
  ((kind)==cudaMemcpyHostToHost?CUDA_MEMCPY_KIND_HTOH:			\
   ((kind)==cudaMemcpyHostToDevice?CUDA_MEMCPY_KIND_HTOD:		\
    ((kind)==cudaMemcpyDeviceToDevice?CUDA_MEMCPY_KIND_DTOD:		\
     ((kind)==cudaMemcpyDeviceToHost?CUDA_MEMCPY_KIND_DTOH:		\
      CUDA_MEMCPY_KIND_UNKNOWN))))

#define CUPTI_ACTIVITY_MEMCPY_KIND_TO_EZT(kind)				\
  ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_HTOD ? CUDA_MEMCPY_KIND_HTOD:	\
   ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_DTOH ? CUDA_MEMCPY_KIND_DTOH:	\
    ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_HTOA ? CUDA_MEMCPY_KIND_HTOA:	\
     ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_ATOH ? CUDA_MEMCPY_KIND_ATOH: \
      ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_ATOA ? CUDA_MEMCPY_KIND_ATOA: \
       ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_ATOD ? CUDA_MEMCPY_KIND_ATOD: \
	((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_DTOA ? CUDA_MEMCPY_KIND_DTOA: \
	 ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_DTOD ? CUDA_MEMCPY_KIND_DTOD: \
	  ((kind) == CUPTI_ACTIVITY_MEMCPY_KIND_HTOH ? CUDA_MEMCPY_KIND_HTOH: \
	   CUDA_MEMCPY_KIND_UNKNOWN)))))))))


/* return true if the transfer starts from the CPU */
#define IS_FROM_CPU(kind)			\
  (((kind) == CUDA_MEMCPY_KIND_HTOD) ||		\
   ((kind) == CUDA_MEMCPY_KIND_HTOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_HTOH))

/* return true if the transfer starts from the GPU */
#define IS_FROM_GPU(kind)			\
  (((kind) == CUDA_MEMCPY_KIND_DTOH) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOH) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOD) ||		\
   ((kind) == CUDA_MEMCPY_KIND_DTOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_DTOD))

/* return true if the transfer ends to the CPU */
#define IS_TO_CPU(kind)				\
  (((kind) == CUDA_MEMCPY_KIND_DTOH) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOH) ||		\
   ((kind) == CUDA_MEMCPY_KIND_HTOH))

/* return true if the transfer ends to the GPU */
#define IS_TO_GPU(kind)				\
  (((kind) == CUDA_MEMCPY_KIND_HTOD) ||		\
   ((kind) == CUDA_MEMCPY_KIND_HTOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOD) ||		\
   ((kind) == CUDA_MEMCPY_KIND_ATOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_DTOA) ||		\
   ((kind) == CUDA_MEMCPY_KIND_DTOD))


#define MEMCPY_TYPE_STR(kind)						\
  ((IS_FROM_CPU(kind) && IS_TO_CPU(kind))? "HToH_memcpy":		\
   (IS_FROM_CPU(kind) && IS_TO_GPU(kind))? "HToD_memcpy":		\
   (IS_FROM_GPU(kind) && IS_TO_CPU(kind))? "DToH_memcpy":		\
   (IS_FROM_GPU(kind) && IS_TO_GPU(kind))? "DToD_memcpy": "Unknown")

extern int __ezt_cuda_initialized;
void __ezt_cuda_initialize();
#define EZT_CUDA_INITIALIZE do { if(!__ezt_cuda_initialized) { __ezt_cuda_initialize(); } } while(0)


#endif
