瀏覽代碼

New functionality starpu_insert_task_array similar to starpu_insert_task but with an array of data_handles.

include: define the function prototype!
src: implementation!
test: add a new test to test the functionality!
doc: documentation!
Nathalie Furmento 12 年之前
父節點
當前提交
3cff53fd54

+ 53 - 2
doc/chapters/advanced-examples.texi

@@ -478,8 +478,17 @@ transfers, which are assumed to be completely overlapped.
 @node Insert Task Utility
 @section Insert Task Utility
 
-StarPU provides the wrapper function @code{starpu_insert_task} to ease
-the creation and submission of tasks.
+StarPU provides wrapper functions @code{starpu_insert_task} and
+@code{starpu_insert_task_array} to ease the creation and submission of tasks.
+
+@menu
+* With a defined number of handles::  
+* With an undefined number of handles::  
+* Task insertion depending on some earlier computation::  
+@end menu
+
+@node With a defined number of handles
+@subsection With a defined number of handles
 
 @deftypefun int starpu_insert_task (struct starpu_codelet *@var{cl}, ...)
 Create and submit a task corresponding to @var{cl} with the following
@@ -596,6 +605,48 @@ task->cl_arg_size = arg_buffer_size;
 int ret = starpu_task_submit(task);
 @end smallexample
 
+@node With an undefined number of handles
+@subsection With an undefined number of handles
+
+@deftypefun int starpu_insert_task_array (struct starpu_codelet *@var{cl}, {starpu_data_handle_t *}@var{handles}, unsigned @var{nb_handles}, ...)
+Create and submit a task corresponding to @var{cl} with the given
+number @var{nb_handles} of @var{handles}, and the following
+arguments.  The argument list must be zero-terminated.
+
+The arguments following the codelets can be of the following types:
+
+@itemize
+@item
+the specific values @code{STARPU_VALUE}, @code{STARPU_CALLBACK},
+@code{STARPU_CALLBACK_ARG}, @code{STARPU_CALLBACK_WITH_ARG},
+@code{STARPU_PRIORITY}, followed by the appropriated objects as
+defined above.
+@end itemize
+
+The number of data handles @var{nb_handles} must be equal to the
+number of data handles expected by the codelet @var{cl}. The access
+modes will be the ones defined by @var{cl}.
+
+Parameters to be passed to the codelet implementation are defined
+through the type @code{STARPU_VALUE}. The function
+@code{starpu_codelet_unpack_args} must be called within the codelet
+implementation to retrieve them.
+@end deftypefun
+
+Here a call to the @code{starpu_insert_task_array} wrapper equivalent
+to the example above.
+
+@smallexample
+starpu_insert_task(&mycodelet,
+                   data_handles, 2,
+                   STARPU_VALUE, &ifactor, sizeof(ifactor),
+                   STARPU_VALUE, &ffactor, sizeof(ffactor),
+                   0);
+@end smallexample
+
+@node Task insertion depending on some earlier computation
+@subsection Task insertion depending on some earlier computation
+
 If some part of the task insertion depends on the value of some computation,
 the @code{STARPU_DATA_ACQUIRE_CB} macro can be very convenient. For
 instance, assuming that the index variable @code{i} was registered as handle

+ 1 - 0
include/starpu_util.h

@@ -249,6 +249,7 @@ int starpu_data_cpy(starpu_data_handle_t dst_handle, starpu_data_handle_t src_ha
 
 /* Wrapper to create a task. */
 int starpu_insert_task(struct starpu_codelet *cl, ...);
+int starpu_insert_task_array(struct starpu_codelet *cl, starpu_data_handle_t *handles, unsigned nb_handles, ...);
 
 /* Retrieve the arguments of type STARPU_VALUE associated to a task
  * automatically created using starpu_insert_task. */

+ 26 - 0
src/util/starpu_insert_task.c

@@ -87,3 +87,29 @@ int starpu_insert_task(struct starpu_codelet *cl, ...)
 	}
         return ret;
 }
+
+int starpu_insert_task_array(struct starpu_codelet *cl, starpu_data_handle_t *handles, unsigned nb_handles, ...)
+{
+	va_list varg_list;
+
+	/* Compute the size */
+	size_t arg_buffer_size = 0;
+	va_start(varg_list, nb_handles);
+        arg_buffer_size = _starpu_insert_task_get_arg_size(varg_list);
+
+	va_start(varg_list, nb_handles);
+	char *arg_buffer;
+	_starpu_codelet_pack_args(arg_buffer_size, &arg_buffer, varg_list);
+
+	va_start(varg_list, nb_handles);
+        struct starpu_task *task = starpu_task_create();
+	int ret = _starpu_insert_task_create_and_submit_array(arg_buffer, arg_buffer_size, cl, &task, handles, nb_handles, varg_list);
+
+	if (ret == -ENODEV)
+	{
+		task->destroy = 0;
+		starpu_task_destroy(task);
+	}
+        return ret;
+
+}

+ 93 - 0
src/util/starpu_insert_task_utils.c

@@ -270,3 +270,96 @@ int _starpu_insert_task_create_and_submit(char *arg_buffer, size_t arg_buffer_si
 
         return ret;
 }
+
+int _starpu_insert_task_create_and_submit_array(char *arg_buffer, size_t arg_buffer_size, struct starpu_codelet *cl, struct starpu_task **task, starpu_data_handle_t *handles, unsigned nb_handles, va_list varg_list)
+{
+	unsigned current_buffer = 0;
+	unsigned i;
+        int arg_type;
+
+	struct insert_task_cb_wrapper *cl_arg_wrapper = (struct insert_task_cb_wrapper *) malloc(sizeof(struct insert_task_cb_wrapper));
+	STARPU_ASSERT(cl_arg_wrapper);
+
+	cl_arg_wrapper->callback_func = NULL;
+	cl_arg_wrapper->arg_stack = arg_buffer;
+
+	for(i=0 ; i<nb_handles ; i++)
+	{
+		(*task)->handles[i] = handles[i];
+	}
+	STARPU_ASSERT(nb_handles == cl->nbuffers);
+
+	while((arg_type = va_arg(varg_list, int)) != 0)
+	{
+		if (arg_type==STARPU_R || arg_type==STARPU_W || arg_type==STARPU_RW || arg_type == STARPU_SCRATCH || arg_type == STARPU_REDUX)
+		{
+			/* We have an access mode : we expect to find a handle */
+			(void) va_arg(varg_list, starpu_data_handle_t);
+			return -EINVAL;
+		}
+		else if (arg_type==STARPU_VALUE)
+		{
+			(void)va_arg(varg_list, void *);
+			(void)va_arg(varg_list, size_t);
+		}
+		else if (arg_type==STARPU_CALLBACK)
+		{
+			void (*callback_func)(void *);
+			callback_func = va_arg(varg_list, _starpu_callback_func_t);
+			cl_arg_wrapper->callback_func = callback_func;
+		}
+		else if (arg_type==STARPU_CALLBACK_WITH_ARG)
+		{
+			void (*callback_func)(void *);
+			void *callback_arg;
+			callback_func = va_arg(varg_list, _starpu_callback_func_t);
+			callback_arg = va_arg(varg_list, void *);
+			cl_arg_wrapper->callback_func = callback_func;
+			cl_arg_wrapper->callback_arg = callback_arg;
+		}
+		else if (arg_type==STARPU_CALLBACK_ARG)
+		{
+			void *callback_arg = va_arg(varg_list, void *);
+			cl_arg_wrapper->callback_arg = callback_arg;
+		}
+		else if (arg_type==STARPU_PRIORITY)
+		{
+			/* Followed by a priority level */
+			int prio = va_arg(varg_list, int);
+			(*task)->priority = prio;
+		}
+		else if (arg_type==STARPU_EXECUTE_ON_NODE)
+		{
+			(void)va_arg(varg_list, int);
+		}
+		else if (arg_type==STARPU_EXECUTE_ON_DATA)
+		{
+			(void)va_arg(varg_list, starpu_data_handle_t);
+		}
+	}
+
+	va_end(varg_list);
+
+	(*task)->cl = cl;
+	(*task)->cl_arg = arg_buffer;
+	(*task)->cl_arg_size = arg_buffer_size;
+
+	/* The callback will free the argument stack and execute the
+	 * application's callback, if any. */
+	(*task)->callback_func = starpu_task_insert_callback_wrapper;
+	(*task)->callback_arg = cl_arg_wrapper;
+
+	int ret = starpu_task_submit(*task);
+
+	if (STARPU_UNLIKELY(ret == -ENODEV))
+	{
+		fprintf(stderr, "submission of task %p wih codelet %p failed (symbol `%s') (err: ENODEV)\n",
+			*task, (*task)->cl,
+			(*task)->cl->name ? (*task)->cl->name :
+			((*task)->cl->model && (*task)->cl->model->symbol)?(*task)->cl->model->symbol:"none");
+		free(cl_arg_wrapper->arg_stack);
+		free(cl_arg_wrapper);
+	}
+
+        return ret;
+}

+ 1 - 0
src/util/starpu_insert_task_utils.h

@@ -24,6 +24,7 @@
 size_t _starpu_insert_task_get_arg_size(va_list varg_list);
 int _starpu_codelet_pack_args(size_t arg_buffer_size, char **arg_buffer, va_list varg_list);
 int _starpu_insert_task_create_and_submit(char *arg_buffer, size_t arg_buffer_size, struct starpu_codelet *cl, struct starpu_task **task, va_list varg_list);
+int _starpu_insert_task_create_and_submit_array(char *arg_buffer, size_t arg_buffer_size, struct starpu_codelet *cl, struct starpu_task **task, starpu_data_handle_t *handles, unsigned nb_handles, va_list varg_list);
 
 #endif // __STARPU_INSERT_TASK_UTILS_H__
 

+ 1 - 0
tests/Makefile.am

@@ -120,6 +120,7 @@ noinst_PROGRAMS =				\
 	main/restart				\
 	main/execute_on_a_specific_worker	\
 	main/insert_task			\
+	main/insert_task_array			\
 	main/multithreaded			\
 	main/multithreaded_init			\
 	main/starpu_task_bundle			\

+ 87 - 0
tests/main/insert_task_array.c

@@ -0,0 +1,87 @@
+/* StarPU --- Runtime system for heterogeneous multicore architectures.
+ *
+ * Copyright (C) 2011, 2012  Centre National de la Recherche Scientifique
+ *
+ * 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 <config.h>
+#include <starpu.h>
+#include "../helper.h"
+
+void func_cpu(void *descr[], void *_args)
+{
+	int *x0 = (int *)STARPU_VARIABLE_GET_PTR(descr[0]);
+	float *x1 = (float *)STARPU_VARIABLE_GET_PTR(descr[1]);
+	int factor;
+
+	starpu_codelet_unpack_args(_args, &factor);
+
+	STARPU_SKIP_IF_VALGRIND;
+        *x0 = *x0 * factor;
+        *x1 = *x1 * (float)factor;
+}
+
+struct starpu_codelet mycodelet =
+{
+	.modes = { STARPU_RW, STARPU_RW },
+	.cpu_funcs = {func_cpu, NULL},
+        .nbuffers = 2
+};
+
+int main(int argc, char **argv)
+{
+        int x; float f;
+	int factor=12;
+        int i, ret;
+        starpu_data_handle_t data_handles[2];
+
+	ret = starpu_init(NULL);
+	if (ret == -ENODEV) return STARPU_TEST_SKIPPED;
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_init");
+
+	x = 1;
+	starpu_variable_data_register(&data_handles[0], 0, (uintptr_t)&x, sizeof(x));
+	f = 2.0;
+	starpu_variable_data_register(&data_handles[1], 0, (uintptr_t)&f, sizeof(f));
+
+        ret = starpu_insert_task_array(&mycodelet, data_handles, 2,
+				       STARPU_VALUE, &factor, sizeof(factor),
+				       STARPU_PRIORITY, 1,
+				       0);
+	if (ret == -ENODEV) goto enodev;
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_insert_task");
+
+        ret = starpu_task_wait_for_all();
+	STARPU_CHECK_RETURN_VALUE(ret, "starpu_task_wait_for_all");
+
+enodev:
+        for(i=0 ; i<2 ; i++)
+	{
+		starpu_data_unregister(data_handles[i]);
+        }
+
+	starpu_shutdown();
+
+	if (ret == -ENODEV)
+	{
+		fprintf(stderr, "WARNING: No one can execute this task\n");
+		/* yes, we do not perform the computation but we did detect that no one
+		 * could perform the kernel, so this is not an error from StarPU */
+		return STARPU_TEST_SKIPPED;
+	}
+	else {
+		FPRINTF(stderr, "VALUES: %d %f\n", x, f);
+		ret = !(x == 12 && f == 24.0);
+		STARPU_RETURN(ret);
+	}
+}