
//..
//..GPUStressW wrapper to call GEMM
//..developed by GTS..
//..
//..Intel(R) Corporation (C) 2015
//..

//..includes
#include "Include/GPUStressW.h"

//..defines
#ifdef __WIN_OS__
//#include "./Include/OlsApi.h"
#include <Windows.h>
#endif
#ifdef __LIN_OS__
#include <stdio.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <fcntl.h>
//#include <sys/ioctl.h>
//#include <unistd.h>
//#include <stdlib.h>
#endif


void ReadLocalConfig(void)
{
	XMLParser localXMLObj;
	try
	{
		int iCFW = td.checkFileExists(sGPUStressWLocalConfigFile);

		if (iCFW == 1)
		{
			//Local config
			localXMLObj.LoadXMLFile(sGPUStressWLocalConfigFile);

			// Set up the root element
			localXMLObj.SetRootElem("GPUStressW_LocalConfig");

			// Get the Default GPU Stress Time
			sGPUStressWTimeInMins = localXMLObj.ReadNodeKeyAsString("@DefaultGPUStressWTimeInMins", "");
			sEXE = localXMLObj.ReadNodeKeyAsString("@EXE", "");
			sGEN9 = localXMLObj.ReadNodeKeyAsString("@GEN9", "");
			sGEN8 = localXMLObj.ReadNodeKeyAsString("@GEN8", "");
			sGEN7 = localXMLObj.ReadNodeKeyAsString("@GEN7", "");
			sGEN6 = localXMLObj.ReadNodeKeyAsString("@GEN6", "");
			sGEN6Pentium = localXMLObj.ReadNodeKeyAsString("@GEN6Pentium", "");
			sGEN6Celeron = localXMLObj.ReadNodeKeyAsString("@GEN6Celeron", "");
			sGEN5 = localXMLObj.ReadNodeKeyAsString("@GEN5", "");
			sGEN4 = localXMLObj.ReadNodeKeyAsString("@GEN4", "");
			sGEN3 = localXMLObj.ReadNodeKeyAsString("@GEN3", "");
			sGEN2 = localXMLObj.ReadNodeKeyAsString("@GEN2", "");
			sCLFILE = localXMLObj.ReadNodeKeyAsString("@CLFILE", "");
						
			//if (bNotSupported)
			//{
			//	iSec = 3;
			//}

			if (iHour == 0 && iMin == 0 && iSec ==0)
			{
				iMin = atoi(sGPUStressWTimeInMins.c_str());
				//std::cout << "..iMin --> " << iMin << std::endl;
			}
			
			//if (iMSZ == 0)
			//{
			//	iMSZ = atoi(sMatrixSize.c_str());
			//	std::cout << "..iMSZ --> " << iMSZ << std::endl;
			//}
		}
		else
		{
			std::cout << std::endl << sGPUStressWLocalConfgFileMsg << std::endl;
			std::cout << "..!!..Exiting..!!.." << std::endl;
			//exit(1);
		}

	}
	catch (...)
	{
		std::string sException;
		sException.append("\n-------------------------------\n");
		sException.append("Cannot locate config file: 'GPUStressW_LocalConfig.xml'! \n");
		sException.append("Application terminated! \n");
		sException.append("\n-------------------------------\n");
		throw(sException);
	}
	return;
}


void Init(void)
{
	tStartTime = std::time(nullptr);
	// Logic needs to be done to determine if this test is a pass or fail.  
	//If indeterminate, it means that the test was interrupted
	igPassFailStatus = ReturnValueDef::Success;  // Success
	//igPassFailStatus = 1;  // Fail
	//igPassFailStatus = 2;  // Indeterminate 
	iColorText = 0;
	iSec = 0;
	iMin = 0;
	iHour = 0;
	iOptionValid = 0;
	iRun = 1;
	iArgIndex = 0;
	iPrintVersionFlag = 1;
	iPrintSuccessFlag = 1;
}

void PrintVersion(void)
{
	std::cout << std::endl << "..." << std::endl << "Version: " << sGPUStressWVersion << std::endl << "..." << std::endl;
}

void SignalFun(int iSigNum)
{
	// If you want to print out the signal, do the following
	cout << "Signal is:" << iSigNum << endl;

	// Depending on your routine, you may want to have some sort of exit message ... however you may also want to comment these out
	cout << endl << "Do the soft clean up here" << endl;
	
	// Do cleanup and close up stuff here 
	CleanUp();

	// Exit the program with one of the accepted error levels. 
	//0 = Success
	//1 = Fail
	//2 = Indeterminate 
	igPassFailStatus = ReturnValueDef::Indeterminate;

    // if you get to this logic, most likely your answer should always be a 2
	std::string sTemp = "Error: " + UtilConvert(igPassFailStatus) + " Indeterminate!";
	PrintColorMsg(sTemp, TextColor::Yellow);
	exit(igPassFailStatus);
}

void CleanUp()
{
	td.RemoveFile(sGPUStressWResultsFile);
}

void WriteResultsFile(int iPassFailStatus)  
{
	// pass fail logic using iPassFailStatus  with 0=pass, 1=fail, 2=indeterminate

	// Write Results File
	td.WriteToFile(sGPUStressWResultsFile, "GPUStressW Module Test");
	std::string sTemp = "Module Version: " + sGPUStressWVersion;
	td.WriteToFile(sGPUStressWResultsFile, sTemp);
	sTemp = "Start Time: ";
	sTemp.append(std::asctime(std::localtime(&tStartTime)));
	td.WriteToFileNoEndL(sGPUStressWResultsFile, sTemp);

	td.WriteToFile(sGPUStressWResultsFile, "GPUStressW Module Test: PASS");	
	if(bNotSupported)
	{
		td.WriteToFile(sGPUStressWResultsFile, "..GPUStressW not supported on this product..");
	}
	//td.WriteToFile(sGPUStressWResultsFile, "SubTest 1: PASS");

	if (igPauseApp)
	{
		PauseWQuit();
	}

	tEndTime = std::time(nullptr);
	sTemp = "End Time: ";
	sTemp.append(std::asctime(std::localtime(&tEndTime)));
	td.WriteToFileNoEndL(sGPUStressWResultsFile, sTemp);

	double seconds = difftime(tEndTime, tStartTime);
	sTemp = "Total Time: ";
	sTemp.append(" seconds: ");
	sTemp.append(UtilConvert(seconds));

	td.WriteToFileNoEndL(sGPUStressWResultsFile, sTemp);
}

void Help(void)
{
	PrintVersion();
	std::cout << std::endl << "Test Information:" << std::endl;
	std::cout << "The purpose of GPUStressW.exe is to add a mathematical load to the GPU device\non the Intel processor.  GPUStressW is developed to run on Intel 4th generation\ncore processors and newer." << std::endl;
	std::cout << std::endl << "..Options are as follows: - " << std::endl;
	std::cout << " -h \t" << "     " << "= This message..\n\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe -h" << std::endl;
	std::cout << std::endl << " -c \t" << "     " << "= If present, this option will output to display the results \n\t" << "       " << "information using the following color scheme: " << std::endl;
	std::cout << "\t" << "       " << "- 'green' - 'PASS' scenario / production unit detected.." << std::endl;
	std::cout << "\t" << "       " << "- 'red' - 'FAIL' scenario / sample unit detected.." << std::endl;
	std::cout << "\t" << "       " << "- 'yellow' - warning message indicating SPBC could not determine\n\t" << "       " << "  if unit is either a sample or production processor.." << std::endl;
	std::cout << "\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe -c" << std::endl;
	std::cout << std::endl <<  " -hrs \t" << "     " <<  "= Hours option - number of hours GPUStressW.exe should run" << std::endl;
	std::cout << "\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe -hrs <integer value> " << std::endl;
	std::cout << std::endl << " -m \t" << "     " << "= Minutes option - number of minutes GPUStressW.exe should run" << std::endl;
	std::cout << "\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe - m <integer value> " << std::endl;
	std::cout << std::endl << " -s \t" << "     " << "= Seconds option - number of seconds GPUStressW.exe should run" << std::endl;
	std::cout << "\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe -s <integer value> " << std::endl;
	std::cout << std::endl << " -info \t" << "     " << "= Information switch that publishes parallel information \n\t" << "       " << "using the following scheme:" << std::endl;
	std::cout << "\t" << "       " << "\"parallel:no|socket:yes|core:yes\" " << std::endl;
	std::cout << std::endl << " -resultName = The resultName switch provides a way to name the results file \n\t" << "       " << "as desired.";
	std::cout << " Otherwise, GPUStressW will generate \n\t" << "       " << "'GPUStressW_Results.txt' file containing the \n\t" << "       " << "results information of the test run.." << std::endl;
	std::cout << "\t" << "       " << "Example:\n\t" << "       " << "GPUStressW.exe -resultName GPU_Results_0001.txt " << std::endl;
	std::cout << std::endl << "Dependencies:" << std::endl;
	std::cout << "\t" << "       " << "GPUStressW_LocalConfig.xml" << std::endl;
	std::cout << "\t" << "       " << "GEMM.exe" << std::endl;
	std::cout << "\t" << "       " << "gemm.cl" << std::endl;
	std::cout << "\t" << "       " << "Intel Graphics Driver" << std::endl;
	std::cout << std::endl << " Copyright (C) 2015, Intel Corporation" << std::endl;
	exit(0);
}

void PauseWQuit(void)
{
	// Pause code
	std::cout << "Please press 'q' <ENTER> to quit: ";
	std::string PauseStr;
	std::cin >> PauseStr;
}

void PrintColorMsg(std::string sMsg, TextColor iColor)
{
	if (iColorText == 0)
	{
		std::cout << std::endl << sMsg << std::endl;
	}
	else
	{
		if (iColor == TextColor::Red)
		{
#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;31m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}
		if (iColor == TextColor::Green)
		{

#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_GREEN | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;32m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}
		if (iColor == TextColor::Yellow)
		{
#ifdef __WIN_OS__
			HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY));
			std::cout << std::endl << sMsg << std::endl;
			SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
			std::cout << "\033[0;33m";
			std::cout << std::endl << sMsg << std::endl;
			std::cout << "\033[0m";
#endif
		}

	}
}
bool is_integer(const std::string & s){
	return std::regex_match(s, std::regex("[0-9]+"));
}
bool isOptionValid(int iArgLocal, int argcLocal, char *argvLocal[], VarType vt)
{
	// Start out as Valid
	bool iRetVal = true;
	std::string sMsg = "";
	std::string sTemp = argvLocal[iArgLocal];

	if (((iArgLocal + 1) < argcLocal) && strlen(argvLocal[iArgLocal + 1]) > 0)
	{
		if (vt == VarType::vtINT)
		{
			if (!is_integer(argvLocal[iArgLocal + 1]))
			{
				iRetVal = false;
				sMsg = "Wrong argument type format for argument: '" + sTemp + "'!";
			}
		}
	}
	else
	{
		// invalid
		iRetVal = false;
		sMsg = "No argument for '" + sTemp + "' detected!";
	}
	// if there was an invalid argument
	if (iRetVal == false)
	{
		PrintColorMsg(sMsg, TextColor::Red);
	}
	return iRetVal;
}

void handleArgs(int argc, char *argv[])
{

	// Optional args
	// Make sure the options can only be run one time
	// Load up all the possible args
	std::vector <string> sArgs_v;
	sArgs_v.push_back("-h");
	sArgs_v.push_back("-c");
	sArgs_v.push_back("-info");
	sArgs_v.push_back("-resultName");
	sArgs_v.push_back("-hrs");
	sArgs_v.push_back("-m");
	sArgs_v.push_back("-s");
	sArgs_v.push_back("-o");

	if (argc > 1)
	{
		for (int iArg = 1; iArg < argc; iArg++)
		{
			for (int iVec = 0; iVec < sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					// Only the options that need to be processed before all the other ones need to be in this list
					if (sArgs_v[iVec] == std::string("-c"))
					{
						iColorText = 1;
					}
				}
			}
		}
		for (int iArg = 1; iArg < argc; iArg++)
		{
			iArgIndex = iArg;
			iOptionValid = 0;
			for (int iVec = 0; iVec < sArgs_v.size(); iVec++)
			{
				if (argv[iArg] == sArgs_v[iVec])
				{
					iOptionValid = 1;
					if (sArgs_v[iVec] == std::string("-h"))
					{
						iRun = 0;
						Help();
					}
					if (sArgs_v[iVec] == std::string("-info"))
					{
						iRun = 0;
						iPrintVersionFlag = 0;
						iPrintSuccessFlag = 0;
						std::cout << "\"parallel:yes|socket:yes|core:yes\"" << std::endl;
					}
					if (sArgs_v[iVec] == std::string("-resultName"))
					{
						sGPUStressWResultsFile = argv[++iArg];
					}
					if (sArgs_v[iVec] == std::string("-o"))
					{
						bOverride = true;
						bNotSupported = false;
					}
					if (sArgs_v[iVec] == std::string("-hrs"))
					{
						// Hours
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iHour = atoi(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}

					}
					if (sArgs_v[iVec] == std::string("-m"))
					{
						// Minutes
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iMin = atoi(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}
					}
					if (sArgs_v[iVec] == std::string("-s"))
					{
						// Seconds
						if (isOptionValid(iArg, argc, argv, VarType::vtINT))
						{
							iSec = atoi(argv[++iArg]);
						}
						else
						{
							iRun = 0;
							iOptionValid = 0;
						}
					}
					if (sArgs_v[iVec] == std::string("-c"))
					{
						std::cout << std::endl << "Entering color text opt" << std::endl;
#ifdef __WIN_OS__
						HANDLE hCommandWindowTextColor = GetStdHandle(STD_OUTPUT_HANDLE);
						SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_GREEN | FOREGROUND_INTENSITY));
						//std::cout << "Some green text ..." << std::endl << std::endl;
						SetConsoleTextAttribute(hCommandWindowTextColor, (FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN));
#endif
#ifdef __LIN_OS__
						std::cout << "\033[1;32m";
						std::cout << std::endl << ".." << std::endl << "Some green text ..." << std::endl << std::endl;
						std::cout << "\033[0m";
#endif
					}
					
					// Erase current vector so the option doesn't repeat
					sArgs_v.erase(sArgs_v.begin() + (iVec));
				}

			}
			if (iDebugFlag)
			{
				std::cout << std::endl << "iOptionValid = " << iOptionValid << std::endl;
			}
			if (iOptionValid == 0)
			{
				break;
			}
		}
		if (iOptionValid == 0)
		{
			std::string sArgTemp = argv[iArgIndex];
			std::string sTempMsg = "Option " + sArgTemp + " invalid!";
			PrintColorMsg(sTempMsg, TextColor::Red);
			iRun = 0;
			igPassFailStatus = ReturnValueDef::InvalidArgs;
			Help();
		}
	}
	else
	{
		// Default message if no arguments are used  ... it may be the useage message or it may be OK that no args are used
		//std::cout << "No args used!!" << std::endl;
	}
}

void PrintSuccess(void)
{
	if (igPassFailStatus == ReturnValueDef::Success)
	{
		if (!bNotSupported)
		{
			PrintColorMsg("GPUStressW Module Success!", TextColor::Green);
		}
		//else
		//{
		//	PrintColorMsg("GPUStressW Not Supported!", TextColor::Green);
		//}
	}
	if (igPassFailStatus == ReturnValueDef::Fail)
	{
		PrintColorMsg("GPUStressW Module Fail!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::Indeterminate)
	{
		PrintColorMsg("GPUStressW Module Interrupted!", TextColor::Yellow);
	}
	if (igPassFailStatus == ReturnValueDef::InvalidArgs)
	{
		PrintColorMsg("GPUStressW Module has invalid arguments!", TextColor::Red);
	}
	if (igPassFailStatus == ReturnValueDef::ConfigMismatch)
	{
		PrintColorMsg("GPUStressW Module has a configuration mismatch!", TextColor::Yellow);
	}	
	if (igPassFailStatus != ReturnValueDef::Success)
	{
		cout << "Return Status = " << igPassFailStatus << endl;
	}
}

void fStartTimer(int iHours, int iMins, int iSec)
{
	start = clock();
	timeElapsed = clock() - start;
	msElapsed = timeElapsed / CLOCKS_PER_MS;
	msTarget = (iSec * 1000) + (iMins * 60 * 1000) + (iHours * 60 * 60 * 1000);
	if (!bNotSupported)
	{
		std::cout << "... Loading GPU ..." << std::endl;
	}
	else
	{
		std::cout << "... Exiting ..." << std::endl;
	}

	for (; msElapsed <= msTarget;)
	{
		timeElapsed = clock() - start;
		msElapsed = timeElapsed / CLOCKS_PER_MS;
	}
}

void fEXE(void)
{
	//std::cout << std::endl << sBuildEXE << std::endl;
	if ((bGen9) || (bGen8) || (bGen7) || (bGen6) || (bGen6Pentium) || (bGen6Celeron) || (bGen5) || (bGen4))
	{
		system(sBuildEXE.c_str());
	}
	else if (bOverride && (bGen3 || bGen2))
	{
		system(sBuildEXE.c_str());
	}
	else
	{
		std::cout << std::endl << "..GPUStressW not supported on this product.." << std::endl;
	}
}

//..read processor brand string
void RetrieveProcessorBrandString()
{
	char sCPUname[iBSmax];

	__asm
	{
		//Get First Part of the Brand String
		mov EAX, 0x80000002
		CPUID

		//Get all byte stored in EAX
		mov sCPUname[0], al
		mov sCPUname[1], ah
		shr EAX, 16
		mov sCPUname[2], al
		mov sCPUname[3], ah

		//Get all byte stored in EBX
		mov sCPUname[4], bl
		mov sCPUname[5], bh
		shr EBX, 16
		mov sCPUname[6], bl
		mov sCPUname[7], bh

		//Get all byte stored in ECX
		mov sCPUname[8], cl
		mov sCPUname[9], ch
		shr ECX, 16
		mov sCPUname[10], cl
		mov sCPUname[11], ch

		//Get all byte stored in EDX
		mov sCPUname[12], dl
		mov sCPUname[13], dh
		shr EDX, 16
		mov sCPUname[14], dl
		mov sCPUname[15], dh

		//Get Second Part of the Brand String
		mov EAX, 0x80000003
		CPUID

		//Get all byte stored in EAX
		mov sCPUname[16], al
		mov sCPUname[17], ah
		shr EAX, 16
		mov sCPUname[18], al
		mov sCPUname[19], ah

		//Get all byte stored in EBX
		mov sCPUname[20], bl
		mov sCPUname[21], bh
		shr EBX, 16
		mov sCPUname[22], bl
		mov sCPUname[23], bh

		//Get all byte stored in ECX
		mov sCPUname[24], cl
		mov sCPUname[25], ch
		shr ECX, 16
		mov sCPUname[26], cl
		mov sCPUname[27], ch

		//Get all byte stored in EDX
		mov sCPUname[28], dl
		mov sCPUname[29], dh
		shr EDX, 16
		mov sCPUname[30], dl
		mov sCPUname[31], dh

		//Get Third Part of the Brand String
		mov EAX, 0x80000004
		CPUID

		//Get all byte stored in EAX
		mov sCPUname[32], al
		mov sCPUname[33], ah
		shr EAX, 16
		mov sCPUname[34], al
		mov sCPUname[35], ah

		//Get all byte stored in EBX
		mov sCPUname[36], bl
		mov sCPUname[37], bh
		shr EBX, 16
		mov sCPUname[38], bl
		mov sCPUname[39], bh

		//Get all byte stored in ECX
		mov sCPUname[40], cl
		mov sCPUname[41], ch
		shr ECX, 16
		mov sCPUname[42], cl
		mov sCPUname[43], ch

		//Get all byte stored in EDX
		mov sCPUname[44], dl
		mov sCPUname[45], dh
		shr EDX, 16
		mov sCPUname[46], dl
		mov sCPUname[47], dh
	}
	sProcessorBrandString.assign(sCPUname);
}

void CheckProcessorBrandString()
{
	std::vector <string> sBrandStringID_v;
	sBrandStringID_v.push_back("i9");
	sBrandStringID_v.push_back("i7");
	sBrandStringID_v.push_back("i5");
	sBrandStringID_v.push_back("i3");
	//sBrandStringID_v.push_back("i5-4");
	sBrandStringID_v.push_back("Pentium");
	sBrandStringID_v.push_back("Celeron");
	//sBrandStringID_v.push_back("i7-6");
	//sBrandStringID_v.push_back("i5-6");
	//sBrandStringID_v.push_back("i3-6");
	//sBrandStringID_v.push_back("i7-5");
	//sBrandStringID_v.push_back("i5-5");
	//sBrandStringID_v.push_back("i3-5");
	//sBrandStringID_v.push_back("i7-4");
	//sBrandStringID_v.push_back("i5-4");
	//sBrandStringID_v.push_back("i3-4");
	//sBrandStringID_v.push_back("i7-3");
	//sBrandStringID_v.push_back("i5-3");
	//sBrandStringID_v.push_back("i3-3");
	//sBrandStringID_v.push_back("i7-2");
	//sBrandStringID_v.push_back("i5-2");
	//sBrandStringID_v.push_back("i3-2");
		
	for (int iVec = 0; iVec < sBrandStringID_v.size(); iVec++)
	{
		stFoundBrandID = sProcessorBrandString.find(sBrandStringID_v[iVec]);
		if (stFoundBrandID != string::npos)
		{
			std::cout << std::endl << "..Found Brand ID - " << sBrandStringID_v[iVec] << std::endl;

			//..gen9
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_9);
			stFoundGenID = sProcessorBrandString.find(sGenID_9);
			if (stFoundGenID != string::npos)
			{
				bGen9 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_9.erase(0, 1) << std::endl;
			}
			
			//..gen8
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_8);
			stFoundGenID = sProcessorBrandString.find(sGenID_8);
			if (stFoundGenID != string::npos)
			{
				bGen8 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_8.erase(0, 1) << std::endl;
			}

			//..gen7
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_7);
			stFoundGenID = sProcessorBrandString.find(sGenID_7);
			if (stFoundGenID != string::npos)
			{
				bGen7 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_7.erase(0, 1) << std::endl;
			}

			//..gen6
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_6);
			stFoundGenID = sProcessorBrandString.find(sGenID_6);
			if (stFoundGenID != string::npos)
			{
				bGen6 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_6.erase(0,1) << std::endl;
			}

			//..gen6pentium
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_6Pentium);
			stFoundGenID = sProcessorBrandString.find(sGenID_6Pentium);
			if (stFoundGenID != string::npos)
			{
				bGen6Pentium = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_6Pentium << std::endl;
			}

			//..gen6celeron
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_6Celeron);
			stFoundGenID = sProcessorBrandString.find(sGenID_6Celeron);
			if (stFoundGenID != string::npos)
			{
				bGen6Celeron = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_6Celeron << std::endl;
			}

			//..gen5
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_5);
			stFoundGenID = sProcessorBrandString.find(sGenID_5);
			if (stFoundGenID != string::npos)
			{
				bGen5 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_5 << std::endl;
			}

			//..gen4
			stFoundGenID = sProcessorBrandString.find(sGenID_4);
			if (stFoundGenID != string::npos)
			{
				bGen4 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_4 << std::endl;
			}

			//..gen3
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_3);
			stFoundGenID = sProcessorBrandString.find(sGenID_3);
			if (stFoundGenID != string::npos)
			{
				bGen3 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_3 << std::endl;
			}

			//..gen2
			//stFoundGenID = sBrandStringID_v[iVec].find(sGenID_2);
			stFoundGenID = sProcessorBrandString.find(sGenID_2);
			if (stFoundGenID != string::npos)
			{
				bGen2 = true;
				std::cout << std::endl << "..Found Gen ID " << sGenID_2 << std::endl;
			}
		}		
	}
}

//..main
int main(int argc, char *argv[])
{
	
	// .W // windows 
#if defined __WIN_64__ 
	sGPUStressWVersion = "1.0.11.64b.W";
#endif

	#if defined __WIN_32__ 
	sGPUStressWVersion = "1.0.11.32b.W";
	#endif

	// .L linux
#if defined __LIN_64__
	sGPUStressWVersion = "1.0.1.64b.L";
#endif
#if defined __LIN_32__
	sGPUStressWVersion = "1.0.1.32b.L";
#endif

	// Need to include signal for Softkill functions
	// If this thread is sent a signal SIGINT, we need to send it to the signal function 
	signal(SIGINT, SignalFun);

	// Parse both text local config style and xml style
	
	Init();
	handleArgs(argc, argv);

	// Print out version
	if (iPrintVersionFlag != 0)
	{
		PrintVersion();
	}

	//..clean up result files ... Clean file before another one is written
	CleanUp();	

	if (iRun)
	{	
		RetrieveProcessorBrandString();
		std::cout << std::endl << sProcessorBrandString << std::endl;

		CheckProcessorBrandString();

		ReadLocalConfig();
		if (bGen9)
		{
			sBuildEXE = sEXE + " " + sGEN9;
		}
		else if (bGen8)
		{
			sBuildEXE = sEXE + " " + sGEN8;
		}
		else if (bGen7)
		{
			sBuildEXE = sEXE + " " + sGEN7;
		}
		else if (bGen6)
		{
			sBuildEXE = sEXE + " " + sGEN6;
		}
		else if (bGen6Pentium)
		{
			sBuildEXE = sEXE + " " + sGEN6Pentium;
		}
		else if (bGen6Celeron)
		{
			sBuildEXE = sEXE + " " + sGEN6Celeron;
		}
		else if(bGen5)
		{
			sBuildEXE = sEXE + " " + sGEN5;
		}
		else if (bGen4)
		{
			sBuildEXE = sEXE + " " + sGEN4;
		}		
		else if (bGen3 && bOverride)
		{
			sBuildEXE = sEXE + " " + sGEN3;
		}		
		else if (bGen2 && bOverride)
		{
			sBuildEXE = sEXE + " " + sGEN2;
		}
		else
		{
			//sBuildEXE = sEXE + " " + sDEFAULT;
			bNotSupported = true;
		}		

		//std::cout << std::endl << "sBuildEXE string --> " << sBuildEXE << std::endl;

		if (!bNotSupported)
		{
			tTimer = new std::thread(fStartTimer, iHour, iMin, iSec);

			tEXE = new std::thread(fEXE);

			tTimer->join();

			WriteResultsFile(igPassFailStatus);

			tEXE->native_handle();

			system(sKILL.c_str());
		}
		else
		{	
			iMin = 0;
			iSec = 1;

			tTimer = new std::thread(fStartTimer, iHour, iMin, iSec);

			tEXE = new std::thread(fEXE);

			tTimer->join();

			WriteResultsFile(0);

			tEXE->native_handle();			
		}
	}
	
	if (iPrintSuccessFlag != 0)
	{
		PrintSuccess();
	}
	if (igPauseApp)
	{
		PauseWQuit();
	}

	return igPassFailStatus;
}
