     }
 }
 
+cudaStream_t* streams;
+
+extern "C" void cuda_create_streams(int num_streams)
+{
+    streams = (cudaStream_t*)malloc(num_streams * sizeof(cudaStream_t));
+    for (int i = 0; i < num_streams; i++) cudaStreamCreate(&streams[i]);
+}
+
+extern "C" void cuda_destroy_streams(int num_streams)
+{
+    for (int i = 0; i < num_streams; i++) cudaStreamDestroy(streams[i]);
+    free(streams);
+}
+
+extern "C" void cuda_stream_synchronize(int stream_id)
+{
+    if (cudaStreamSynchronize(streams[stream_id]) != cudaSuccess)
+    {
+        printf("failed to execute cudaStreamSynchronize()\n");
+        exit(0);
+    }
+}
+
+extern "C" void cuda_async_copy_to_device(void *target, void *source, size_t size, int stream_id)
+{
+    cudaStream_t stream = (stream_id == -1) ? NULL : streams[stream_id];
+
+    if (cudaMemcpyAsync(target, source, size, cudaMemcpyHostToDevice, stream) != cudaSuccess)
+    {
+        printf("failed to execute cudaMemcpy(cudaMemcpyHostToDevice)\n");
+        exit(0);
+    }
+}
+
+extern "C" void cuda_async_copy_to_host(void *target, void *source, size_t size, int stream_id)
+{
+    cudaStream_t stream = (stream_id == -1) ? NULL : streams[stream_id];
+
+    if (cudaMemcpyAsync(target, source, size, cudaMemcpyDeviceToHost, stream) != cudaSuccess)
+    {
+        printf("failed to execute cudaMemcpy(cudaMemcpyDeviceToHost)\n");
+        exit(0);
+    }
+}
+
 extern "C" void cuda_memset(void *ptr,int value, size_t size)
 {
     if (cudaMemset(ptr, value, size) != cudaSuccess)

    }
}

//* 
//* extern "C" void gpu_zhegvx(int32_t n, int32_t nv, double abstol, void *a, void *b,
//*                            double *eval, void *z, int32_t ldz)
//* {
//*     magma_int_t m1, info;
//* 
//*     magma_int_t nb = magma_get_zhetrd_nb(n);
//*     magma_int_t lwork = 2 * n * (nb + 1);
//*     magma_int_t lrwork = 7 * n;
//*     magma_int_t liwork = 6 * n;
//*     
//*     cuDoubleComplex *h_work;
//*     double *rwork, *w1;
//*     magma_int_t *iwork, *ifail;
//*     
//*     w1 = (double *)malloc(n * sizeof(double));
//*     h_work = (cuDoubleComplex *)malloc(lwork * sizeof(cuDoubleComplex));
//*     rwork = (double *)malloc(lrwork * sizeof(double));
//*     iwork = (magma_int_t *)malloc(liwork * sizeof(magma_int_t));
//*     ifail = iwork + 5 * n;
//* 
//*     magma_zhegvx(1, 'V', 'I', 'U', n, (cuDoubleComplex *)a, n, (cuDoubleComplex *)b, n, 0.0, 0.0, 1, nv, abstol, 
//*                  &m1, w1, (cuDoubleComplex *)z, ldz, h_work, lwork, rwork, iwork, ifail, &info);
//* 
//*     memcpy(eval, &w1[0], nv * sizeof(double)); 
//*     
//*     free(iwork);
//*     free(rwork);
//*     free(w1);
//*     free(h_work);
//* }
//*  

// A(GPU) => B(CPU)
extern "C" void cublas_get_matrix(int rows, int cols, int elemSize, const void *A, int lda, void *B, int ldb)
{

//* 
//*     return devprop;
//* }

extern "C" void cuda_device_info()
{
