/*
 *  -- MAGMA (version 1.1) --
 *     Univ. of Tennessee, Knoxville
 *     Univ. of California, Berkeley
 *     Univ. of Colorado, Denver
 *     November 2011
 *
 *  @generated s Fri Nov 22 14:21:30 2013
 *
 **/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "flops.h"
#include "magma.h"
#include "magma_lapack.h"
#include "testings.h"

int main(int argc, char **argv)
{
	/* Initialize */
	magma_queue_t  queue;
	magma_device_t device;
	int num = 0;
	magma_err_t err;
	magma_init();
	err = magma_get_devices( &device, 1, &num );
	if ( err != MAGMA_SUCCESS or num < 1 ) {
		fprintf( stderr, "magma_get_devices failed: %d\n", err );
		exit(-1);
	}
	err = magma_queue_create( device, &queue );
	if ( err != MAGMA_SUCCESS ) {
		fprintf( stderr, "magma_queue_create failed: %d\n", err );
		exit(-1);
	}

	real_Double_t   gflops, mic_perf, mic_time, cpu_perf, cpu_time;
	float          mic_error, work[1];
	magma_int_t ione     = 1;
	magma_int_t ISEED[4] = {0,0,0,1};
	magma_int_t M, N, Xm, Ym, lda, sizeA, sizeX, sizeY;
	magma_int_t incx = 1;
	magma_int_t incy = 1;
	float c_neg_one = MAGMA_S_NEG_ONE;
	float alpha = MAGMA_S_MAKE(  1.5, -2.3 );
	float beta  = MAGMA_S_MAKE( -0.6,  0.8 );
	float *A, *X, *Y, *Ymic;
	float *dA, *dX, *dY;

	magma_opts opts;
	parse_opts( argc, argv, &opts );

	printf("    M     N   MIC Gflop/s (ms)   CPU Gflop/s (ms)  MIC error\n");
	printf("============================================================\n");
	for( int i = 0; i < opts.ntest; ++i ) {
		for( int iter = 0; iter < opts.niter; ++iter ) {
			M = opts.msize[i];
			N = opts.nsize[i];
			lda    = ((M+31)/32)*32;
			gflops = FLOPS_SGEMV( M, N ) / 1e9;

			if ( opts.transA == MagmaNoTrans ) {
				Xm = N;
				Ym = M;
			} else {
				Xm = M;
				Ym = N;
			}

			sizeA = lda*N;
			sizeX = incx*Xm;
			sizeY = incy*Ym;

			TESTING_MALLOC_HOST( A, float, sizeA );
			TESTING_MALLOC_HOST( X, float, sizeX );
			TESTING_MALLOC_HOST( Y, float, sizeY );
			TESTING_MALLOC_HOST( Ymic, float, sizeY );

			TESTING_MALLOC_DEV( dA, float, sizeA );
			TESTING_MALLOC_DEV( dX, float, sizeX );
			TESTING_MALLOC_DEV( dY, float, sizeY );

			/* Initialize the matrix */
			lapackf77_slarnv( &ione, ISEED, &sizeA, A );
			lapackf77_slarnv( &ione, ISEED, &sizeX, X );
			lapackf77_slarnv( &ione, ISEED, &sizeY, Y );

			/* =====================================================================
			   Performs operation using MIC
			   =================================================================== */
			magma_ssetmatrix( M, N, A, 0, lda, dA, 0, lda, queue );
			//magma_ssetvector( Xm, X, incx, dX, incx );
			//magma_ssetvector( Ym, Y, incy, dY, incy );
			magma_ssetmatrix( Xm, 1, X, 0, Xm, dX, 0, Xm, queue );
			magma_ssetmatrix( Ym, 1, Y, 0, Ym, dY, 0, Ym, queue );

			magma_sgemv( opts.transA, M, N, alpha, dA, 0, lda, dX, 0, incx, beta, dY, 0, incy, queue );

			magma_ssetmatrix( Ym, 1, Y, 0, Ym, dY, 0, Ym, queue );

			mic_time = magma_sync_wtime( 0 );
			magma_sgemv( opts.transA, M, N, alpha, dA, 0, lda, dX, 0, incx, beta, dY, 0, incy, queue );
			mic_time = magma_sync_wtime( 0 ) - mic_time;
			mic_perf = gflops / mic_time;

			if(opts.check) {
				//magma_sgetvector( Ym, dY, incy, Ymic, incy );
				magma_sgetmatrix( Ym, 1, dY, 0, Ym, Ymic, 0, Ym, queue );

				/* =====================================================================
				   Performs operation using CPU BLAS
				   =================================================================== */
				cpu_time = magma_wtime();
				blasf77_sgemv( lapack_const(opts.transA), &M, &N,
						&alpha, A, &lda,
						X, &incx,
						&beta,  Y, &incy );
				cpu_time = magma_wtime() - cpu_time;
				cpu_perf = gflops / cpu_time;

				/* =====================================================================
				   Check the result
				   =================================================================== */
				blasf77_saxpy( &Ym, &c_neg_one, Y, &incy, Ymic, &incy );
				mic_error = lapackf77_slange( "M", &Ym, &ione, Ymic, &Ym, work ) / Ym;

				printf("%5d %5d   %7.2f (%7.2f)   %7.2f (%7.2f)	%8.2e\n",
						(int) M, (int) N,
						mic_perf, 1000.*mic_time,
						cpu_perf,    1000.*cpu_time,
						mic_error );
			} else {
				printf("%5d %5d   %7.2f (%7.2f)   --- (---)	---\n",
						(int) M, (int) N,
						mic_perf, 1000.*mic_time);

			}

			TESTING_FREE_HOST( A );
			TESTING_FREE_HOST( X );
			TESTING_FREE_HOST( Y );
			TESTING_FREE_HOST( Ymic );

			TESTING_FREE_DEV( dA );
			TESTING_FREE_DEV( dX );
			TESTING_FREE_DEV( dY );
		}
		if ( opts.niter > 1 ) {
			printf( "\n" );
		}
	}

	magma_queue_destroy( queue );
	magma_finalize();

	return 0;
}
