@c -*-texinfo-*- @c This file is part of the StarPU Handbook. @c Copyright (C) 2009--2011 Universit@'e de Bordeaux 1 @c Copyright (C) 2010, 2011, 2012 Centre National de la Recherche Scientifique @c Copyright (C) 2011, 2012 Institut National de Recherche en Informatique et Automatique @c See the file starpu.texi for copying conditions. @menu * Defining a new data interface:: * Multiformat Data Interface:: * Task Bundles:: * Task Lists:: * Using Parallel Tasks:: * Scheduling Contexts:: * Defining a new scheduling policy:: * Running drivers:: * Expert mode:: @end menu @node Defining a new data interface @section Defining a new data interface @menu * Data Interface API:: Data Interface API * An example of data interface:: An example of data interface @end menu @node Data Interface API @subsection Data Interface API @deftp {Data Type} {struct starpu_data_interface_ops} @anchor{struct starpu_data_interface_ops} Per-interface data transfer methods. @table @asis @item @code{void (*register_data_handle)(starpu_data_handle_t handle, uint32_t home_node, void *data_interface)} Register an existing interface into a data handle. @item @code{starpu_ssize_t (*allocate_data_on_node)(void *data_interface, uint32_t node)} Allocate data for the interface on a given node. @item @code{ void (*free_data_on_node)(void *data_interface, uint32_t node)} Free data of the interface on a given node. @item @code{ const struct starpu_data_copy_methods *copy_methods} ram/cuda/spu/opencl synchronous and asynchronous transfer methods. @item @code{ void * (*handle_to_pointer)(starpu_data_handle_t handle, uint32_t node)} Return the current pointer (if any) for the handle on the given node. @item @code{ size_t (*get_size)(starpu_data_handle_t handle)} Return an estimation of the size of data, for performance models. @item @code{ uint32_t (*footprint)(starpu_data_handle_t handle)} Return a 32bit footprint which characterizes the data size. @item @code{ int (*compare)(void *data_interface_a, void *data_interface_b)} Compare the data size of two interfaces. @item @code{ void (*display)(starpu_data_handle_t handle, FILE *f)} Dump the sizes of a handle to a file. @item @code{ int (*convert_to_gordon)(void *data_interface, uint64_t *ptr, gordon_strideSize_t *ss)} Convert the data size to the spu size format. If no SPUs are used, this field can be seto NULL. @item @code{enum starpu_data_interface_id interfaceid} An identifier that is unique to each interface. @item @code{size_t interface_size} The size of the interface data descriptor. @item @code{int is_multiformat} todo @item @code{struct starpu_multiformat_data_interface_ops* (*get_mf_ops)(void *data_interface)} todo @item @code{int (*pack_data)(starpu_data_handle_t handle, uint32_t node, void **ptr)} Pack the data handle into a contiguous buffer at the address @code{ptr} @item @code{int (*unpack_data)(starpu_data_handle_t handle, uint32_t node, void *ptr)} Unpack the data handle from the contiguous buffer at the address @code{ptr} @end table @end deftp @deftp {Data Type} {struct starpu_data_copy_methods} Defines the per-interface methods. @table @asis @item @code{int @{ram,cuda,opencl,spu@}_to_@{ram,cuda,opencl,spu@}(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node)} These 16 functions define how to copy data from the @var{src_interface} interface on the @var{src_node} node to the @var{dst_interface} interface on the @var{dst_node} node. They return 0 on success. @item @code{int (*ram_to_cuda_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, cudaStream_t stream)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (in RAM) to the @var{dst_interface} interface on the @var{dst_node} node (on a CUDA device), using the given @var{stream}. Return 0 on success. @item @code{int (*cuda_to_ram_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, cudaStream_t stream)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (on a CUDA device) to the @var{dst_interface} interface on the @var{dst_node} node (in RAM), using the given @var{stream}. Return 0 on success. @item @code{int (*cuda_to_cuda_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, cudaStream_t stream)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (on a CUDA device) to the @var{dst_interface} interface on the @var{dst_node} node (on another CUDA device), using the given @var{stream}. Return 0 on success. @item @code{int (*ram_to_opencl_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, /* cl_event * */ void *event)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (in RAM) to the @var{dst_interface} interface on the @var{dst_node} node (on an OpenCL device), using @var{event}, a pointer to a cl_event. Return 0 on success. @item @code{int (*opencl_to_ram_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, /* cl_event * */ void *event)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (on an OpenCL device) to the @var{dst_interface} interface on the @var{dst_node} node (in RAM), using the given @var{event}, a pointer to a cl_event. Return 0 on success. @item @code{int (*opencl_to_opencl_async)(void *src_interface, unsigned src_node, void *dst_interface, unsigned dst_node, /* cl_event * */ void *event)} Define how to copy data from the @var{src_interface} interface on the @var{src_node} node (on an OpenCL device) to the @var{dst_interface} interface on the @var{dst_node} node (on another OpenCL device), using the given @var{event}, a pointer to a cl_event. Return 0 on success. @end table @end deftp @deftypefun uint32_t starpu_crc32_be_n ({void *}@var{input}, size_t @var{n}, uint32_t @var{inputcrc}) Compute the CRC of a byte buffer seeded by the inputcrc "current state". The return value should be considered as the new "current state" for future CRC computation. This is used for computing data size footprint. @end deftypefun @deftypefun uint32_t starpu_crc32_be (uint32_t @var{input}, uint32_t @var{inputcrc}) Compute the CRC of a 32bit number seeded by the inputcrc "current state". The return value should be considered as the new "current state" for future CRC computation. This is used for computing data size footprint. @end deftypefun @deftypefun uint32_t starpu_crc32_string ({char *}@var{str}, uint32_t @var{inputcrc}) Compute the CRC of a string seeded by the inputcrc "current state". The return value should be considered as the new "current state" for future CRC computation. This is used for computing data size footprint. @end deftypefun @node An example of data interface @subsection An example of data interface @deftypefun int starpu_data_interface_get_next_id (void) Returns the next available id for a newly created data interface. @end deftypefun Let's define a new data interface to manage complex numbers. @cartouche @smallexample /* interface for complex numbers */ struct starpu_complex_interface @{ double *real; double *imaginary; int nx; @}; @end smallexample @end cartouche Registering such a data to StarPU is easily done using the function @code{starpu_data_register} (@pxref{Basic Data Management API}). The last parameter of the function, @code{interface_complex_ops}, will be described below. @cartouche @smallexample void starpu_complex_data_register(starpu_data_handle_t *handle, uint32_t home_node, double *real, double *imaginary, int nx) @{ struct starpu_complex_interface complex = @{ .real = real, .imaginary = imaginary, .nx = nx @}; if (interface_complex_ops.interfaceid == -1) @{ interface_complex_ops.interfaceid = starpu_data_interface_get_next_id(); @} starpu_data_register(handleptr, home_node, &complex, &interface_complex_ops); @} @end smallexample @end cartouche Different operations need to be defined for a data interface through the type @code{struct starpu_data_interface_ops} (@pxref{Data Interface API}). We only define here the basic operations needed to run simple applications. The source code for the different functions can be found in the file @code{examples/interface/complex_interface.c}. @cartouche @smallexample static struct starpu_data_interface_ops interface_complex_ops = @{ .register_data_handle = complex_register_data_handle, .allocate_data_on_node = complex_allocate_data_on_node, .copy_methods = &complex_copy_methods, .get_size = complex_get_size, .footprint = complex_footprint, .interfaceid = -1, .interface_size = sizeof(struct starpu_complex_interface), @}; @end smallexample @end cartouche Functions need to be defined to access the different fields of the complex interface from a StarPU data handle. @cartouche @smallexample double *starpu_complex_get_real(starpu_data_handle_t handle) @{ struct starpu_complex_interface *complex_interface = (struct starpu_complex_interface *) starpu_data_get_interface_on_node(handle, 0); return complex_interface->real; @} double *starpu_complex_get_imaginary(starpu_data_handle_t handle); int starpu_complex_get_nx(starpu_data_handle_t handle); @end smallexample @end cartouche Similar functions need to be defined to access the different fields of the complex interface from a @code{void *} pointer to be used within codelet implemetations. @cartouche @smallexample #define STARPU_COMPLEX_GET_REAL(interface) \ (((struct starpu_complex_interface *)(interface))->real) #define STARPU_COMPLEX_GET_IMAGINARY(interface) \ (((struct starpu_complex_interface *)(interface))->imaginary) #define STARPU_COMPLEX_GET_NX(interface) \ (((struct starpu_complex_interface *)(interface))->nx) @end smallexample @end cartouche Complex data interfaces can then be registered to StarPU. @cartouche @smallexample double real = 45.0; double imaginary = 12.0; starpu_complex_data_register(&handle1, 0, &real, &imaginary, 1); starpu_insert_task(&cl_display, STARPU_R, handle1, 0); @end smallexample @end cartouche and used by codelets. @cartouche @smallexample void display_complex_codelet(void *descr[], __attribute__ ((unused)) void *_args) @{ int nx = STARPU_COMPLEX_GET_NX(descr[0]); double *real = STARPU_COMPLEX_GET_REAL(descr[0]); double *imaginary = STARPU_COMPLEX_GET_IMAGINARY(descr[0]); int i; for(i=0 ; itype} is not a valid StarPU device type (STARPU_CPU_WORKER, STARPU_CUDA_WORKER or STARPU_OPENCL_WORKER). This is the same as using the following functions: calling @code{starpu_driver_init()}, then calling @code{starpu_driver_run_once()} in a loop, and eventually @code{starpu_driver_deinit()}. @end deftypefun @deftypefun int starpu_driver_init (struct starpu_driver *@var{d}) Initialize the given driver. Returns 0 on success, -EINVAL if @code{d->type} is not a valid StarPU device type (STARPU_CPU_WORKER, STARPU_CUDA_WORKER or STARPU_OPENCL_WORKER). @end deftypefun @deftypefun int starpu_driver_run_once (struct starpu_driver *@var{d}) Run the driver once, then returns 0 on success, -EINVAL if @code{d->type} is not a valid StarPU device type (STARPU_CPU_WORKER, STARPU_CUDA_WORKER or STARPU_OPENCL_WORKER). @end deftypefun @deftypefun int starpu_driver_deinit (struct starpu_driver *@var{d}) Deinitialize the given driver. Returns 0 on success, -EINVAL if @code{d->type} is not a valid StarPU device type (STARPU_CPU_WORKER, STARPU_CUDA_WORKER or STARPU_OPENCL_WORKER). @end deftypefun @deftypefun void starpu_drivers_request_termination (void) Notify all running drivers they should terminate. @end deftypefun @node Example @subsection Example @cartouche @smallexample int ret; struct starpu_driver = @{ .type = STARPU_CUDA_WORKER, .id.cuda_id = 0 @}; ret = starpu_driver_init(&d); if (ret != 0) error(); while (some_condition) @{ ret = starpu_driver_run_once(&d); if (ret != 0) error(); @} ret = starpu_driver_deinit(&d); if (ret != 0) error(); @end smallexample @end cartouche @node Expert mode @section Expert mode @deftypefun void starpu_wake_all_blocked_workers (void) Wake all the workers, so they can inspect data requests and task submissions again. @end deftypefun @deftypefun int starpu_progression_hook_register (unsigned (*@var{func})(void *arg), void *@var{arg}) Register a progression hook, to be called when workers are idle. @end deftypefun @deftypefun void starpu_progression_hook_deregister (int @var{hook_id}) Unregister a given progression hook. @end deftypefun