Explorar el Código

Multiformat : assume that the data structures used on CUDA devices and OpenCL
devices are the same.

A conversion should only be needed when copying data from
a CPU to a GPU, or the other way around.

Add a test case : multiformat_cuda_opencl.c

Some code that can easily be reused in order to test handle conversions can be
found in generic.{c,h}.

Cyril Roelandt hace 13 años
padre
commit
44b8640205

+ 38 - 1
src/core/task.c

@@ -466,5 +466,42 @@ _starpu_handle_needs_conversion_task(starpu_data_handle_t handle,
 
 	node_kind = _starpu_get_node_kind(node);
 
-	return !!(node_kind != _starpu_get_node_kind(handle->mf_node));
+	/*
+	 * Here, we assume that CUDA devices and OpenCL devices use the 
+	 * same data structure. A conversion is only needed when moving 
+	 * data from a CPU to a GPU, or the other way around.
+	 */
+	switch (node_kind)
+	{
+		case STARPU_CPU_RAM:
+			switch(_starpu_get_node_kind(handle->mf_node))
+			{
+				case STARPU_CPU_RAM:
+					return 0;
+				case STARPU_CUDA_RAM:      /* Fall through */
+				case STARPU_OPENCL_RAM:
+					return 1;
+				case STARPU_SPU_LS: /* Not supported */
+				default:
+					STARPU_ASSERT(0);
+			}
+			break;
+		case STARPU_CUDA_RAM:    /* Fall through */
+		case STARPU_OPENCL_RAM:
+			switch(_starpu_get_node_kind(handle->mf_node))
+			{
+				case STARPU_CPU_RAM:
+					return 1;
+				case STARPU_CUDA_RAM:
+				case STARPU_OPENCL_RAM:
+					return 0;
+				case STARPU_SPU_LS: /* Not supported */
+				default:
+					STARPU_ASSERT(0);
+			}
+			break;
+		case STARPU_SPU_LS:            /* Not supported */
+		default:
+			STARPU_ASSERT(0);
+	}
 }

+ 11 - 1
tests/Makefile.am

@@ -32,7 +32,8 @@ EXTRA_DIST =					\
 	datawizard/interfaces/vector/test_vector_opencl_kernel.cl \
 	datawizard/interfaces/multiformat/multiformat_types.h \
 	datawizard/interfaces/multiformat/multiformat_opencl_kernel.cl \
-	datawizard/interfaces/multiformat/multiformat_conversion_codelets_kernel.cl
+	datawizard/interfaces/multiformat/multiformat_conversion_codelets_kernel.cl \
+	datawizard/interfaces/multiformat/advanced/generic.h
 
 CLEANFILES = 					\
 	*.gcno *.gcda *.linkinfo		\
@@ -161,6 +162,7 @@ noinst_PROGRAMS =				\
 	datawizard/lazy_allocation		\
 	datawizard/interfaces/matrix/matrix_interface \
 	datawizard/interfaces/multiformat/multiformat_interface \
+	datawizard/interfaces/multiformat/advanced/multiformat_cuda_opencl \
 	datawizard/interfaces/variable/variable_interface    \
 	datawizard/interfaces/vector/test_vector_interface   \
 	errorcheck/starpu_init_noworker		\
@@ -307,6 +309,10 @@ nobase_STARPU_OPENCL_DATA_DATA+= \
 	datawizard/interfaces/matrix/matrix_opencl_kernel.cl
 endif
 
+
+#########################
+# Multiformat interface #
+#########################
 datawizard_interfaces_multiformat_multiformat_interface_SOURCES =           \
 	datawizard/interfaces/test_interfaces.c                             \
 	datawizard/interfaces/multiformat/multiformat_interface.c           \
@@ -327,6 +333,10 @@ nobase_STARPU_OPENCL_DATA_DATA +=
 	datawizard/interfaces/multiformat/multiformat_conversion_codelets_kernel.cl
 endif
 
+datawizard_interfaces_multiformat_advanced_multiformat_cuda_opencl_SOURCES=\
+	datawizard/interfaces/multiformat/advanced/generic.c               \
+	datawizard/interfaces/multiformat/advanced/multiformat_cuda_opencl.c
+
 datawizard_interfaces_variable_variable_interface_SOURCES=   \
 	datawizard/interfaces/test_interfaces.c              \
 	datawizard/interfaces/variable/variable_interface.c

+ 159 - 0
tests/datawizard/interfaces/multiformat/advanced/generic.c

@@ -0,0 +1,159 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011  Institut National de Recherche en Informatique et Automatique
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+#include <starpu_data_interfaces.h>
+#include "generic.h"
+#include "../../../../common/helper.h"
+
+struct stats global_stats;
+
+#ifdef STARPU_USE_CUDA
+void cuda_func(void *buffers[], void *args)
+{
+	global_stats.cuda++;
+}
+
+void cpu_to_cuda_func(void *buffers[], void *args)
+{
+	global_stats.cpu_to_cuda++;
+}
+
+void cuda_to_cpu_func(void *buffers[], void *args)
+{
+	global_stats.cuda_to_cpu++;
+}
+
+struct starpu_codelet cpu_to_cuda_cl = {
+	.where = STARPU_CUDA,
+	.cuda_func = cpu_to_cuda_func,
+	.nbuffers = 1
+};
+
+struct starpu_codelet cuda_to_cpu_cl = {
+	.where = STARPU_CPU,
+	.cpu_func = cuda_to_cpu_func,
+	.nbuffers = 1
+};
+#endif /* !STARPU_USE_CUDA */
+
+#ifdef STARPU_USE_OPENCL
+void opencl_func(void *buffers[], void *args)
+{
+	global_stats.opencl++;
+}
+
+void cpu_to_opencl_func(void *buffers[], void *args)
+{
+	global_stats.cpu_to_opencl++;
+}
+
+void opencl_to_cpu_func(void *buffers[], void *args)
+{
+	global_stats.opencl_to_cpu++;
+}
+
+struct starpu_codelet cpu_to_opencl_cl = {
+	.where = STARPU_OPENCL,
+	.opencl_func = cpu_to_opencl_func,
+	.nbuffers = 1
+};
+
+struct starpu_codelet opencl_to_cpu_cl = {
+	.where = STARPU_CPU,
+	.cpu_func = opencl_to_cpu_func,
+	.nbuffers = 1
+};
+#endif /* !STARPU_USE_OPENCL */
+
+
+struct starpu_multiformat_data_interface_ops ops = {
+#ifdef STARPU_USE_CUDA
+	.cuda_elemsize = sizeof(int),
+	.cpu_to_cuda_cl = &cpu_to_cuda_cl,
+	.cuda_to_cpu_cl = &cuda_to_cpu_cl,
+#endif
+#ifdef STARPU_USE_OPENCL
+	.opencl_elemsize = sizeof(int),
+	.cpu_to_opencl_cl = &cpu_to_opencl_cl,
+	.opencl_to_cpu_cl = &opencl_to_cpu_cl,
+#endif
+	.cpu_elemsize = sizeof(int)
+};
+
+void
+print_stats(struct stats *s)
+{
+#ifdef STARPU_USE_CPU
+	FPRINTF(stderr, "cpu         : %d\n", s->cpu);
+#endif /* !STARPU_USE_CPU */
+#ifdef STARPU_USE_CUDA
+	FPRINTF(stderr, "cuda        : %d\n" 
+			"cpu->cuda   : %d\n"
+			"cuda->cpu   : %d\n",
+			s->cuda,
+			s->cpu_to_cuda,
+			s->cuda_to_cpu);
+#endif /* !STARPU_USE_CUDA */
+#ifdef STARPU_USE_OPENCL
+	FPRINTF(stderr, "opencl      : %d\n" 
+			"cpu->opencl : %d\n"
+			"opencl->cpu : %d\n",
+			s->opencl,
+			s->cpu_to_opencl,
+			s->opencl_to_cpu);
+#endif /* !STARPU_USE_OPENCL */
+}
+
+void reset_stats(struct stats *s)
+{
+#ifdef STARPU_USE_CPU
+	s->cpu = 0;
+#endif /* !STARPU_USE_CPU */
+#ifdef STARPU_USE_CUDA
+	s->cuda = 0;
+	s->cpu_to_cuda = 0;
+	s->cuda_to_cpu = 0;
+#endif /* !STARPU_USE_CUDA */
+#ifdef STARPU_USE_OPENCL
+	s->opencl = 0;
+	s->cpu_to_opencl = 0;
+	s->opencl_to_cpu = 0;
+#endif /* !STARPU_USE_OPENCL */
+}
+
+int
+compare_stats(struct stats *s1, struct stats *s2)
+{
+	if (
+#ifdef STARPU_USE_CPU
+	    s1->cpu == s2->cpu &&
+#endif /* !STARPU_USE_CPU */
+#ifdef STARPU_USE_CUDA
+	    s1->cuda == s2->cuda &&
+	    s1->cpu_to_cuda == s2->cpu_to_cuda &&
+	    s1->cuda_to_cpu == s2->cuda_to_cpu &&
+#endif /* !STARPU_USE_CUDA */
+#ifdef STARPU_USE_OPENCL
+	    s1->opencl == s2->opencl &&
+	    s1->cpu_to_opencl == s2->cpu_to_opencl &&
+	    s1->opencl_to_cpu == s2->opencl_to_cpu &&
+#endif /* !STARPU_USE_OPENCL */
+	    1 /* Just so the build does not fail if we disable EVERYTHING */
+	)
+		return 0;
+	else
+		return 1;
+
+}

+ 50 - 0
tests/datawizard/interfaces/multiformat/advanced/generic.h

@@ -0,0 +1,50 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011  Institut National de Recherche en Informatique et Automatique
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+#ifndef MULTIFORMAT_GENERIC_H
+#define MULTIFORMAT_GENERIC_H
+
+#define NX 16
+
+#ifdef STARPU_USE_CUDA
+void cuda_func(void *buffers[], void *args);
+#endif /* !STARPU_USE_CUDA */
+
+#ifdef STARPU_USE_OPENCL
+void opencl_func(void *buffers[], void *args);
+#endif /* !STARPU_USE_OPENCL */
+extern struct starpu_multiformat_data_interface_ops ops;
+/* Counting the calls to the codelets */
+struct stats {
+#ifdef STARPU_USE_CPU
+	unsigned int cpu;
+#endif
+#ifdef STARPU_USE_CUDA
+	unsigned int cuda;
+	unsigned int cpu_to_cuda;
+	unsigned int cuda_to_cpu;
+#endif
+#ifdef STARPU_USE_OPENCL
+	unsigned int opencl;
+	unsigned int cpu_to_opencl;
+	unsigned int opencl_to_cpu;
+#endif
+};
+
+void print_stats(struct stats *);
+void reset_stats(struct stats *);
+int  compare_stats(struct stats *, struct stats *);
+
+#endif /* !MULTIFORMAT_GENERIC_H */

+ 153 - 0
tests/datawizard/interfaces/multiformat/advanced/multiformat_cuda_opencl.c

@@ -0,0 +1,153 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011  Institut National de Recherche en Informatique et Automatique
+ *
+ * StarPU is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * StarPU is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU Lesser General Public License in COPYING.LGPL for more details.
+ */
+#include <starpu.h>
+
+#include "generic.h"
+#include "../../../../common/helper.h"
+
+extern struct stats global_stats;
+static int vector[NX];
+static starpu_data_handle_t handle;
+
+/*
+ * Initially, our vector should be in RAM. It is then used on a CUDA device,
+ * then on an OpenCL device, and finally, on a CUDA device again.
+ * The following operations should be performed, in this specific order :
+ * - CPU -> CUDA conversion
+ * - CUDA kernel execution
+ * - OpenCL kernel execution
+ * - CUDA kernel execution
+ * - CUDA -> CPU conversion
+ *
+ * Note that we will not run any conversion between CUDA and OpenCL, because
+ * StarPU assumes that the data structures used on CUDA and OpenCL devices are
+ * the same.
+ */
+#if defined(STARPU_USE_CUDA) && defined(STARPU_USE_OPENCL)
+static int
+test(void)
+{
+	int ret;
+	struct starpu_task *task_cuda, *task_cuda2, *task_opencl;
+
+	static struct starpu_codelet cl_cuda =
+	{
+		.where     = STARPU_CUDA,
+		.cuda_func = cuda_func,
+		.nbuffers  = 1
+	};
+
+	task_cuda = starpu_task_create();
+	task_cuda->cl = &cl_cuda;
+	task_cuda->buffers[0].handle = handle;
+	task_cuda->buffers[0].mode = STARPU_RW;
+	ret = starpu_task_submit(task_cuda);
+	if (ret != 0)
+		return 1; 
+
+	static struct starpu_codelet cl_opencl =
+	{
+		.where       = STARPU_OPENCL,
+		.opencl_func = opencl_func,
+		.nbuffers    = 1
+	};
+
+	task_opencl = starpu_task_create();
+	task_opencl->cl = &cl_opencl;
+	task_opencl->buffers[0].handle = handle;
+	task_opencl->buffers[0].mode = STARPU_RW;
+	ret = starpu_task_submit(task_opencl);
+	if (ret != 0)
+		return 1;
+
+	task_cuda2 = starpu_task_create();
+	task_cuda2->cl = &cl_cuda;
+	task_cuda2->buffers[0].handle = handle;
+	task_cuda2->buffers[0].mode = STARPU_RW;
+	ret = starpu_task_submit(task_cuda2);
+	if (ret != 0)
+		return 1;
+
+	return 0;
+}
+#endif /* !(STARPU_USE_CUDA && STARPU_USE_OPENCL) */
+
+static void
+register_handle(void)
+{
+	int i;
+	for (i = 0; i < NX; i++)
+		vector[i] = i;
+	starpu_multiformat_data_register(&handle, 0, vector, NX, &ops);
+}
+
+static void
+unregister_handle(void)
+{
+	starpu_data_unregister(handle);
+}
+
+int
+main(void)
+{
+#if defined(STARPU_USE_CUDA) && defined(STARPU_USE_OPENCL)
+	int ret;
+	struct starpu_conf conf =
+	{
+		.ncpus   = -1,
+		.ncuda   = 1,
+		.nopencl = 1
+	};
+
+	ret = starpu_init(&conf);
+	if (ret == -ENODEV)
+		goto enodev;
+
+	reset_stats(&global_stats);
+	register_handle();
+	ret = test();
+	unregister_handle();
+	starpu_shutdown();
+
+	if (ret != 0)
+		return STARPU_TEST_SKIPPED;
+
+	struct stats expected_stats =
+	{
+		.cpu           = 0,
+		.cuda          = 2,
+		.cpu_to_cuda   = 1,
+		.cuda_to_cpu   = 1,
+		.opencl        = 1,
+		.cpu_to_opencl = 0,
+		.opencl_to_cpu = 0
+	};
+	
+	ret = compare_stats(&global_stats, &expected_stats);
+	if (ret != 0)
+	{
+		print_stats(&global_stats);
+		print_stats(&expected_stats);
+		return EXIT_FAILURE;
+	}
+
+	return EXIT_SUCCESS;
+enodev:
+	return STARPU_TEST_SKIPPED;
+#else
+	return STARPU_TEST_SKIPPED;
+#endif
+}