/*      systester-cli.c
//      
//      Copyright 2005-2011 Lucas Tsatiris <systester.project@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program 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 General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.
//      
*/      


/*
 * This is the CLI version of System Stability Tester
 */

#include <string.h>
#include <math.h>
#include <gmp.h>
#include "systester.h"
#include "compthreads.h"
#include "pi.h"

#if !defined(_LITE)
#include "config.h"
#include "native.h"
#include "types.h"
#include "cpufreq.cpp"
#include "cpuid.cpp"
#include "dmifreq.cpp"
#include "mem.cpp"
#include "ncpus.cpp"
#include "util.cpp"
#include "winsmbios.cpp"
#endif /* _LITE */

#include "checksum.cpp"
#include "compthreads.cpp"
#include "gausslegendre.cpp"
#include "osid.cpp"
#include "qcborwein.cpp"
#include "master.cpp"
#include "pitimer.cpp"
#include "outtime.cpp"
#include "outxdigits.cpp"

/* Valid digits selected by user */
char cli_digits_upper[][5] =
  { "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M", "32M", "64M",
  "128M"
};

char cli_digits_lower[][5] =
  { "128k", "256k", "512k", "1m", "2m", "4m", "8m", "16m", "32m", "64m",
  "128m"
};

/* Print the intro screen */
void
intro ()
{
  unsigned long long freq;
  int cpu, activecpus;
  char osstring[80], ChipID[64] = "", VendorID[64] = "",
    gmpverstring[12], xstr[255];

#if !defined(_LITE)
  cpu = CPUID (ChipID, VendorID);
  activecpus = ncpus ();
  freq = cpufreq ();
#endif

  osid (osstring);

#if defined(_LITE)
  sprintf (xstr, "\nSystem Stability Tester. LITE Version %d.%d.%d.\n",
	   SYSTESTER_MAJOR, SYSTESTER_MINOR, SYSTESTER_PATCH);
#else
  sprintf (xstr, "\nSystem Stability Tester. CLI Version %d.%d.%d.\n",
	   SYSTESTER_MAJOR, SYSTESTER_MINOR, SYSTESTER_PATCH);
#endif

  PRINT ("%s", xstr);
  PRINT ("%s", "Distributed under the terms of the GPL v2.\n");
  PRINT ("%s", "Type -help for command line options.\n");
  PRINT ("%s", "http://systester.sourceforge.net\n\n");

#if !defined(_LITE)
  PRINT ("%s\n", ChipID);

  sprintf (xstr, "Running %s at %ld MHz\n", osstring, (long) freq);
  PRINT ("%s", xstr);

  sprintf (xstr, "System memory: %d MB\nHardware threads: %d\n",
	   (int) (totalmem () / (1024 * 1024)), activecpus);
  PRINT ("%s", xstr);
#else
  sprintf (xstr, "Running %s\n", osstring);
  PRINT ("%s", xstr);
#endif

  sprintf (gmpverstring, "GMP %s", gmp_version);
  PRINT ("GMP version: %s\n", gmpverstring);
  sprintf (xstr, "Compiler used for GMP: %s with flags:\n", __GMP_CC);
  PRINT ("%s", xstr);
  sprintf (xstr, "%s\n", __GMP_CFLAGS); 
  PRINT ("%s", xstr);

  sprintf (xstr, "Compiled for %d bit environments\n\n",
	   (int) (sizeof (int *) * 8));
  PRINT ("%s", xstr);


}

/* Print the help screen */
void
help ()
{
  char xstr[256];
  intro ();
  PRINT ("%s\n", "Valid command line options");
  PRINT ("%s\n", " -help                  Prints this help screen");
  PRINT ("%s\n",
	 " -qcborwein <digits>	Use Borwein's Quadratic Convergence algorithm");
  PRINT ("%s\n", " -gausslg  <digits>     Use Gauss-Legendre algorithm");
  PRINT ("%s\n\n",
	 "  Valid <digits> values: 128K, 256K, 512K, 1M, 2M, 4M, 8M, 16M, 32M, 64M, 128M");

  sprintf (xstr,
	   " -threads <nthreads>    The number of threads. Default 1, Maximum %d",
	   MAX_THREADS);
  PRINT ("%s\n", xstr);
  PRINT ("%s\n", " -turns <nturns>        The number of turns. Default 1");
  PRINT ("%s\n",
	 " -test                  Set operating mode to Test. This is the default");
  PRINT ("%s\n", " -bench                 Set operating mode to Bench");
  PRINT ("%s\n", " -log                   Create the systester.log file");
  PRINT ("%s\n\n", " -pifile                Create the CPUPI.DAT file");
#if defined(_LITE)
  PRINT ("%s\n", "EXAMPLE for Unix systems:");
  PRINT ("%s\n", "./systester-lite -gausslg 1M -threads 2 -bench");
#else
  PRINT ("%s\n", "EXAMPLE for Unix systems:");
  PRINT ("%s\n", "./systester-cli -gausslg 1M -threads 2 -bench");
#endif
}

/* Determine the loops according to the selected algorithm */
int
determine_loops (char *cli_digits, int algo)
{
  int loops = -1, i;

  for (i = 0; i < 11; i++)
    if (strcmp (cli_digits_upper[i], cli_digits) == 0)
      loops = i;

  for (i = 0; i < 11; i++)
    if (strcmp (cli_digits_lower[i], cli_digits) == 0)
      loops = i;

  if (loops > -1)
    {
      if (algo == 0)
	loops += 16;
      else
	loops += 17;
    }

  return loops;
}

/* As it says */
int
main (int argc, char *argv[])
{
  int loops, executions, threads, algo, arg, counter;

/* Default settings */
  pflag = 0;
  lflag = 0;
  algo = 0;			/* Borwein */
  mode = 0;			/* Test */
  loops = 16;			/* 128 K */
  threads = 1;
  executions = 1;

/* Argument parsing */
  if (argc > 1)
    {
      arg = 1;
      while (arg < argc)
	{
	  if (strcmp (argv[arg], "-qcborwein") == 0)
	    {
	      algo = 0;
	      arg++;
	      loops = determine_loops (argv[arg], algo);
	      if (loops == -1)
		{
		  help ();
		  exit (0);
		}
	    }
	  else if (strcmp (argv[arg], "-gausslg") == 0)
	    {
	      algo = 1;
	      arg++;
	      loops = determine_loops (argv[arg], algo);
	      if (loops == -1)
		{
		  help ();
		  exit (0);
		}
	    }
	  else if (strcmp (argv[arg], "-threads") == 0)
	    {
	      arg++;
	      threads = atoi (argv[arg]);

	      if (threads < 1)
		{
		  help ();
		  exit (0);
		}

	      if (threads > MAX_THREADS)
		threads = MAX_THREADS;

	    }
	  else if (strcmp (argv[arg], "-turns") == 0)
	    {
	      arg++;
	      executions = atoi (argv[arg]);
	      if (executions < 1)
		executions = 1;
	    }
	  else if (strcmp (argv[arg], "-test") == 0)
	    mode = 0;
	  else if (strcmp (argv[arg], "-bench") == 0)
	    mode = 1;
	  else if (strcmp (argv[arg], "-pifile") == 0)
	    pflag = 1;
	  else if (strcmp (argv[arg], "-log") == 0)
	    lflag = 1;
	  else
	    {
	      help ();
	      exit (0);
	    }

	  arg++;
	}
    }

/* Shoot */
  intro ();

  PRINT ("%s", " Operating mode: ");
  if (mode == 0)
    PRINT ("%s\n", "Test");
  else
    PRINT ("%s\n", "Bench");

  start = pitimer ();
  for (counter = 0; counter < executions; counter++)
    {
      pass++;
      master ((unsigned long long) loops, threads, algo);
      printf ("\n");
    }

  return 0;
}
