/* StarPU --- Runtime system for heterogeneous multicore architectures.
 *
 * Copyright (C) 2010-2011, 2013-2014, 2020-2021  Université de Bordeaux 1
 * Copyright (C) 2010  Mehdi Juhoor <mjuhoor@gmail.com>
 * Copyright (C) 2010, 2011, 2012, 2013, 2014  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.
 */

/*
 * This example shows a simple implementation of a blocked matrix
 * multiplication. Note that this is NOT intended to be an efficient
 * implementation of sgemm! In this example, we show:
 *  - how to declare dense matrices (starpu_matrix_data_register)
 *  - how to manipulate matrices within codelets (eg. descr[0].blas.ld)
 *  - how to use filters to partition the matrices into blocks
 *    (starpu_data_partition and starpu_data_map_filters)
 *  - how to unpartition data (starpu_data_unpartition) and how to stop
 *    monitoring data (starpu_data_unregister)
 *  - how to manipulate subsets of data (starpu_data_get_sub_data)
 *  - how to construct an autocalibrated performance model (starpu_perfmodel)
 *  - how to submit asynchronous tasks
 */

#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>

#include <starpu.h>

#include "mult.h"

static float *A, *B, *C;
static starpu_data_handle_t A_handle, B_handle, C_handle;

unsigned nslicesx = 4;
unsigned nslicesy = 4;
unsigned xdim = 1024;
unsigned ydim = 1024;
unsigned zdim = 512;

/*
 * That program should compute C = A * B
 *
 *   A of size (z,y)
 *   B of size (x,z)
 *   C of size (x,y)

              |---------------|
            z |       B       |
              |---------------|
       z              x
     |----|   |---------------|
     |    |   |               |
     |    |   |               |
     | A  | y |       C       |
     |    |   |               |
     |    |   |               |
     |----|   |---------------|

 */

int main(int argc, char **argv)
{
	int ret;
	double start, stop, duration;
	double gflop;
	unsigned ncpus;

	parse_args(argc, argv);

	/* start the runtime */
	struct starpu_conf conf;
	starpu_conf_init(&conf);
	ret = starpu_init(&conf);
	if (ret == -ENODEV)
		return 77;
	STARPU_CHECK_RETURN_VALUE(ret, "starpu_init");

	ncpus = starpu_cpu_worker_get_count();
	if (ncpus == 0)
		return 77;

	/* initialize matrices A, B and C and register them to StarPU */
	init_problem_data(&A, &B, &C);

	/* partition matrices into blocks that can be manipulated by the
	 * codelets */
	partition_mult_data(A, B, C, &A_handle, &B_handle, &C_handle);

	start = starpu_timing_now();
	/* submit all tasks in an asynchronous fashion */
	ret = launch_tasks(A_handle, B_handle, C_handle);
	if (ret == -ENODEV) goto enodev;

	/* wait for termination */
	starpu_task_wait_for_all();
	stop = starpu_timing_now();

	duration = stop - start;
	gflop = 2.*xdim*ydim*zdim;
	printf("%.3fs	%.3fGFlop/s\n", duration / 1000000., (gflop / duration) / 1000.);

	unpartition_mult_data(A_handle, B_handle, C_handle);

	free(A);
	free(B);
	free(C);

	starpu_shutdown();

	return 0;

enodev:
	starpu_shutdown();
	return 77;
}

