
/*******************************************************************************
*
* File time3.c
*
* Copyright (C) 2008 Bjorn Leder, 2016 Jacob Finkenrath
*
* This software is distributed under the terms of the GNU General Public
* License (GPL)
*
* QCD speed test
*
*******************************************************************************/

#define MAIN_PROGRAM

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mpi.h"
#include "su3.h"
#include "global.h"
#include "bm.h"
#include "flags.h"
#include "random.h"
#include "su3fcts.h"
#include "utils.h"
#include "lattice.h"
#include "uflds.h"
#include "archive.h"
#include "forces.h"
#include "update.h"
#include "version.h"
#include "sw_term.h"
#include "dirac.h"

#if (((L0%4)!=0)||((L1%4)!=0)||((L2%4)!=0)||((L3%4)!=0))
#error: The local lattice sizes must be a multiple of 4
#endif


int kernel_c()
{
   int my_rank,nb, kernel_number=2;
   double cg_wdt[3],cgd_wdt[3],msap_wdt,ahat_wdt,wdt;
   FILE *flog=NULL;

   /* JuBE */
   /* call jube initial function */
   jube_kernel_init(&kernel_number);

/*    MPI_Init(&argc,&argv); */
   MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);

   if (my_rank==0)
   {
/*       flog=freopen("time3.log","w",stdout); */
/*       error_root(flog==NULL,1,"main [time3.c]","Unable to open log file"); */

     flog = stdout;

      printf("\n");
      printf("QCD speed test\n");      
      printf("-------------------------------\n\n");

      printf("%dx%dx%dx%d lattice, ",NPROC0*L0,NPROC1*L1,NPROC2*L2,NPROC3*L3);
      printf("%dx%dx%dx%d process grid, ",NPROC0,NPROC1,NPROC2,NPROC3);
      printf("%dx%dx%dx%d local lattice\n\n",L0,L1,L2,L3);

      if (NPROC>1)
         printf("There are %d MPI processes\n",NPROC);
      else
         printf("There is 1 MPI process\n");
      
#if (defined SSE3)
      printf("Using inline assembly SSE3 instructions\n");
#elif (defined SSE2)
      printf("Using inline assembly SSE2 instructions\n");      
#elif (defined SSE)
      printf("Using inline assembly SSE instructions\n");
#endif

#if (defined SSE)
#if (defined P3)
      printf("Assuming SSE prefetch instructions fetch 32 bytes\n");
#elif (defined PM)
      printf("Assuming SSE prefetch instructions fetch 64 bytes\n");
#elif (defined P4)
      printf("Assuming SSE prefetch instructions fetch 128 bytes\n");
#else
      printf("SSE prefetch instructions are not used\n");
#endif
#endif
      
      printf("\n");
   }

   /* JuBE */
   /* call jube run function */
   jube_kernel_run();
   
   time_cg_iter(flog,cg_wdt);
   time_cg_iter_dble(flog,cgd_wdt);
   time_msap(flog,&msap_wdt);
   time_Awhat(flog,&ahat_wdt,&nb);
   
   /* JuBE */
   /* call jube finalize function */
   jube_kernel_finalize();

   wdt=2.0*cg_wdt[0]+3.0*cg_wdt[1]+2.0*cg_wdt[2];
   
   if (my_rank==0)
   {
      printf("\n");
      printf("#########################################################\n");
      printf("#                                                       #\n");
      printf("#             SYNTHETIC QCD SPEED TEST                  #\n");
      printf("#                                                       #\n");
      printf("#  Using single-precision (%d bit) data and programs    #\n",
             8*(int)(sizeof(float)));
      printf("#                                                       #\n");
      printf("#   Time per lattice point:  %8.3f micro sec         #\n",
             wdt);
      printf("#   Average speed:           %8.3f Gflops/process    #\n",
             1.0e-3*4200.0/wdt);
      printf("#   Total throughput:        %8.3f Gflops            #\n",
             1.0e-3*(double)(NPROC)*4200.0/wdt);
      printf("#                                                       #\n");
   }   
      
   wdt=2.0*cgd_wdt[0]+3.0*cgd_wdt[1]+2.0*cgd_wdt[2];
      
   if (my_rank==0)
   {
      printf("#                                                       #\n");
      printf("#  Using double-precision (%d bit) data and programs    #\n",
             8*(int)(sizeof(double)));
      printf("#                                                       #\n");
      printf("#   Time per lattice point:  %8.3f micro sec         #\n",
             wdt);
      printf("#   Average speed:           %8.3f Gflops/process    #\n",
             1.0e-3*4200.0/wdt);
      printf("#   Total throughput:        %8.3f Gflops            #\n",
             1.0e-3*(double)(NPROC)*4200.0/wdt);
      printf("#                                                       #\n");
   }   
   
   if (my_rank==0)
   {
      printf("#                                                       #\n");
      printf("#  Using the Schwarz preconditioner [%d bit arithmetic] #\n",
             8*(int)(sizeof(float)));
      printf("#                                                       #\n");
      printf("#   Time per lattice point:  %8.3f micro sec         #\n",
             msap_wdt);
      printf("#   Average speed:           %8.3f Gflops/process    #\n",
             1.0e-3*((double)((NMR+1)*2076+48)+112.0*2.0)/msap_wdt);
      printf("#   Total throughput:        %8.3f Gflops            #\n",
             1.0e-3*((double)((NMR+1)*2076+48)+112.0*2.0)/msap_wdt);
      printf("#                                                       #\n");
   }   
   
   if (my_rank==0)
   {
      printf("#                                                       #\n");
      printf("#  Using deflation (little Dirac operator)              #\n");
      printf("#  [%d bit arithmetic]                                  #\n",
             (int)(4*sizeof(complex)));
      printf("#                                                       #\n");
      printf("#   Time per lattice point:  %8.3f micro sec         #\n",
             ahat_wdt/(double)(VOLUME));
      printf("#   Average speed:           %8.3f Gflops/process    #\n",
             1.0e-3*64.0*(double)(nb*NS*NS)/ahat_wdt);
      printf("#   Total throughput:        %8.3f Gflops            #\n",
             1.0e-3*64.0*(double)(NPROC*nb*NS*NS)/ahat_wdt);
      printf("#                                                       #\n");
      printf("#########################################################\n\n");
      
/*       fclose(flog); */
   }   
   
/*    MPI_Finalize(); */
   
   /* JuBE */
  /* call jube end function */
  jube_kernel_end();

  return 0;
}
