Check process exit codes + various other improvements.
This commit is contained in:
parent
b29af3da73
commit
aa3be5e316
@ -36,7 +36,7 @@
|
||||
|
||||
#define DEFAULT_EXEC_LOOPS 10
|
||||
#define DEFAULT_WARMUP_LOOPS 3
|
||||
#define DEFAULT_LOGFILE _T("TimedExec.log")
|
||||
#define DEFAULT_LOGFILE "TimedExec.log"
|
||||
#define ENABLE_ENV_VARS true
|
||||
|
||||
#ifdef _UNICODE
|
||||
@ -54,7 +54,7 @@ static volatile bool g_aborted = false;
|
||||
|
||||
static bool getEnvVariable(const _TCHAR *const name, tstring &value)
|
||||
{
|
||||
const size_t BUFF_SIZE = 512;
|
||||
const size_t BUFF_SIZE = 1024;
|
||||
_TCHAR buffer[BUFF_SIZE];
|
||||
|
||||
const DWORD ret = GetEnvironmentVariable(name, buffer, BUFF_SIZE);
|
||||
@ -109,7 +109,7 @@ static bool checkBinary(const tstring &filePath)
|
||||
|
||||
static tstring getFullPath(const _TCHAR *const fileName)
|
||||
{
|
||||
const size_t BUFF_SIZE = 512;
|
||||
const size_t BUFF_SIZE = 1024;
|
||||
_TCHAR buffer[BUFF_SIZE];
|
||||
|
||||
const DWORD ret = GetFullPathName(fileName, BUFF_SIZE, buffer, NULL);
|
||||
@ -121,6 +121,23 @@ static tstring getFullPath(const _TCHAR *const fileName)
|
||||
return tstring(fileName);
|
||||
}
|
||||
|
||||
static tstring getFileNameOnly(const tstring &filePath)
|
||||
{
|
||||
static _TCHAR *FILTER = _T(":?*/\\<>|");
|
||||
|
||||
tstring result(filePath);
|
||||
for(size_t i = 0; FILTER[i]; i++)
|
||||
{
|
||||
size_t pos;
|
||||
if((pos = result.rfind(FILTER[i])) != tstring::npos)
|
||||
{
|
||||
result.erase(0, ++pos);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int initializeCommandLine(tstring &commandLine, tstring &programFile)
|
||||
{
|
||||
commandLine.clear();
|
||||
@ -165,21 +182,6 @@ static int initializeCommandLine(tstring &commandLine, tstring &programFile)
|
||||
return nArgs;
|
||||
}
|
||||
|
||||
static tstring getFileNameOnly(const tstring &filePath)
|
||||
{
|
||||
tstring result(filePath);
|
||||
static _TCHAR *FILTER = _T(":?*/\\<>|");
|
||||
for(size_t i = 0; FILTER[i]; i++)
|
||||
{
|
||||
size_t pos;
|
||||
if((pos = result.rfind(FILTER[i])) != tstring::npos)
|
||||
{
|
||||
result.erase(0, pos);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool createProcess(const tstring &commandLine, HANDLE &hThrd, HANDLE &hProc, const bool suspended = false)
|
||||
{
|
||||
STARTUPINFO startInfo;
|
||||
@ -213,22 +215,33 @@ static bool waitForProcess(const HANDLE &hProc)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int getProcessExitCode(const HANDLE &hProc)
|
||||
{
|
||||
DWORD exitCode;
|
||||
if(GetExitCodeProcess(hProc, &exitCode))
|
||||
{
|
||||
return *reinterpret_cast<int*>(&exitCode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void abortedHandlerRoutine(const HANDLE &hProc)
|
||||
{
|
||||
TerminateProcess(hProc, UINT(-1));
|
||||
WaitForSingleObject(hProc, INFINITE);
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "ABORTED BY USER !!!" << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
}
|
||||
|
||||
static void invalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t)
|
||||
{
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "GURU MEDITATION: Invalid Parameter Handler Invoked!" << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
@ -257,13 +270,13 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
std::ios initFmt(NULL);
|
||||
initFmt.copyfmt(std::cerr);
|
||||
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "Timed Exec - Benchmarking Utility, Version " << VERSION_MAJOR << '.' << std::setfill('0') << std::setw(2) << VERSION_MINOR << " [" __DATE__ "]" << std::endl;
|
||||
std::cerr << "Copyright (c) 2014 LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.\n" << std::endl;
|
||||
std::cerr << "This program is free software: you can redistribute it and/or modify" << std::endl;
|
||||
std::cerr << "it under the terms of the GNU General Public License <http://www.gnu.org/>." << std::endl;
|
||||
std::cerr << "Note that this program is distributed with ABSOLUTELY NO WARRANTY." << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
|
||||
std::cerr.copyfmt(initFmt);
|
||||
|
||||
@ -277,9 +290,10 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << " TimedExec.exe <Program.exe> [Arguments]\n" << std::endl;
|
||||
std::cerr << "Influential environment variables:" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_LOGFILE - Log File (default: \"" << DEFAULT_LOGFILE << "\")" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_PASSES - Number of execution passes (default: " << DEFAULT_EXEC_LOOPS << ")" << std::endl;
|
||||
std::cerr << " TIMED_WARMUP_PASSES - Number of warm-up passes (default: " << DEFAULT_WARMUP_LOOPS << ")\n" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_PASSES - Number of execution passes (default: " << DEFAULT_EXEC_LOOPS << ")" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_WARMUP_PASSES - Number of warm-up passes (default: " << DEFAULT_WARMUP_LOOPS << ")" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_LOGFILE - Log-File Name (default: \"" << DEFAULT_LOGFILE << "\")" << std::endl;
|
||||
std::cerr << " TIMED_EXEC_NO_CHECKS - Set this to *disable* exit code checks\n" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@ -299,8 +313,9 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
/* Check Environment Variables */
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
tstring logFile(DEFAULT_LOGFILE);
|
||||
tstring logFile(getFullPath(_T(DEFAULT_LOGFILE)));
|
||||
int maxPasses = DEFAULT_EXEC_LOOPS, maxWarmUpPasses = DEFAULT_WARMUP_LOOPS;
|
||||
bool checkExitCodes = true;
|
||||
|
||||
if(ENABLE_ENV_VARS)
|
||||
{
|
||||
@ -309,13 +324,17 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
maxPasses = std::max(3, _tstoi(temp.c_str()));
|
||||
}
|
||||
if(getEnvVariable(_T("TIMED_WARMUP_PASSES"), temp))
|
||||
if(getEnvVariable(_T("TIMED_EXEC_WARMUP_PASSES"), temp))
|
||||
{
|
||||
maxWarmUpPasses = std::max(0, _tstoi(temp.c_str()));
|
||||
}
|
||||
if(getEnvVariable(_T("TIMED_EXEC_LOGFILE"), temp))
|
||||
{
|
||||
logFile.swap(temp);
|
||||
logFile = getFullPath(temp.c_str());
|
||||
}
|
||||
if(getEnvVariable(_T("TIMED_EXEC_NO_CHECKS"), temp))
|
||||
{
|
||||
checkExitCodes = (_tstoi(temp.c_str()) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +344,7 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
|
||||
_ftprintf(stderr, _T("Command-line:\n%s\n\n"), commandLine.c_str());
|
||||
_ftprintf(stderr, _T("Log File:\n%s\n\n"), logFile.c_str());
|
||||
std::cerr << "Number of Warm-Up/Metering passes: " << maxPasses << "x / " << maxWarmUpPasses << 'x' << std::endl;
|
||||
std::cerr << "Warm-Up / Metering passes: " << maxWarmUpPasses << "x / " << maxPasses << 'x' << std::endl;
|
||||
|
||||
const LONGLONG timerFrequency = getTimerFrequency();
|
||||
if(!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS))
|
||||
@ -347,9 +366,9 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
|
||||
for(int pass = 0; pass < maxWarmUpPasses; pass++)
|
||||
{
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "WARM-UP PASS " << (pass + 1) << " OF " << maxWarmUpPasses << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
|
||||
HANDLE hThrd, hProc;
|
||||
|
||||
@ -371,6 +390,17 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const int exitCode = getProcessExitCode(hProc);
|
||||
if(checkExitCodes && (exitCode != 0))
|
||||
{
|
||||
std::cerr << "\n\nPROGRAM ERROR: Abnormal program termination detected! (Exit Code: " << exitCode << ")\n" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\n>> Process terminated with exit code " << exitCode << '.' << std::endl;
|
||||
}
|
||||
|
||||
CloseHandle(hThrd);
|
||||
CloseHandle(hProc);
|
||||
}
|
||||
@ -381,9 +411,9 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
|
||||
for(int pass = 0; pass < maxPasses; pass++)
|
||||
{
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "METERING PASS " << (pass + 1) << " OF " << maxPasses << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
|
||||
HANDLE hThrd, hProc;
|
||||
|
||||
@ -417,13 +447,24 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CloseHandle(hThrd);
|
||||
CloseHandle(hProc);
|
||||
const int exitCode = getProcessExitCode(hProc);
|
||||
if(checkExitCodes && (exitCode != 0))
|
||||
{
|
||||
std::cerr << "\n\nPROGRAM ERROR: Abnormal program termination detected! (Exit Code: " << exitCode << ")\n" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\n>> Process terminated with exit code " << exitCode << '.' << std::endl;
|
||||
}
|
||||
|
||||
std::cerr << std::setprecision(3) << std::fixed;
|
||||
std::cerr << "\n--> Execution took " << execTime << " seconds." << std::endl;
|
||||
std::cerr << ">> Execution took " << execTime << " seconds." << std::endl;
|
||||
std::cerr.copyfmt(initFmt);
|
||||
|
||||
CloseHandle(hThrd);
|
||||
CloseHandle(hProc);
|
||||
|
||||
if(execTime > stats_slowest) stats_slowest = execTime;
|
||||
if(execTime < stats_fastest) stats_fastest = execTime;
|
||||
|
||||
@ -449,17 +490,17 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
const double confidenceInterval_99 = 2.576 * standardError;
|
||||
|
||||
std::cerr << std::setprecision(3) << std::fixed;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "TEST COMPLETED SUCCESSFULLY AFTER " << maxPasses << " METERING PASSES" << std::endl;
|
||||
std::cerr << "---------------------------------------------------------------------------" << std::endl;
|
||||
std::cerr << "-------------------------------------------------------------------------------" << std::endl;
|
||||
std::cerr << "Mean Execution Time : " << stats_mean << " seconds" << std::endl;
|
||||
std::cerr << "90% Confidence Interval : +/- " << confidenceInterval_90 << " = [" << (stats_mean - confidenceInterval_90) << ", " << (stats_mean + confidenceInterval_90) << "] seconds" << std::endl;
|
||||
std::cerr << "95% Confidence Interval : +/- " << confidenceInterval_95 << " = [" << (stats_mean - confidenceInterval_95) << ", " << (stats_mean + confidenceInterval_95) << "] seconds" << std::endl;
|
||||
std::cerr << "99% Confidence Interval : +/- " << confidenceInterval_99 << " = [" << (stats_mean - confidenceInterval_99) << ", " << (stats_mean + confidenceInterval_99) << "] seconds" << std::endl;
|
||||
std::cerr << "90% Confidence Interval : +/- " << confidenceInterval_90 << " (" << 100.0 * (confidenceInterval_90 / stats_mean) << "%) = [" << (stats_mean - confidenceInterval_90) << ", " << (stats_mean + confidenceInterval_90) << "] seconds" << std::endl;
|
||||
std::cerr << "95% Confidence Interval : +/- " << confidenceInterval_95 << " (" << 100.0 * (confidenceInterval_95 / stats_mean) << "%) = [" << (stats_mean - confidenceInterval_95) << ", " << (stats_mean + confidenceInterval_95) << "] seconds" << std::endl;
|
||||
std::cerr << "99% Confidence Interval : +/- " << confidenceInterval_99 << " (" << 100.0 * (confidenceInterval_99 / stats_mean) << "%) = [" << (stats_mean - confidenceInterval_99) << ", " << (stats_mean + confidenceInterval_99) << "] seconds" << std::endl;
|
||||
std::cerr << "Standard Deviation : " << standardDeviation << " seconds" << std::endl;
|
||||
std::cerr << "Standard Error : " << standardError << " seconds" << std::endl;
|
||||
std::cerr << "Fastest / Slowest Pass : " << stats_fastest << " / " << stats_slowest << " seconds" << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
std::cerr.copyfmt(initFmt);
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
@ -471,14 +512,22 @@ static int timedExecMain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
if(getCurrentFileSize(fLog) == 0)
|
||||
{
|
||||
_ftprintf_s(fLog, _T("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n"), _T("Program"), _T("Passes"), _T("Mean Time"), _T("90% Confidence Interval"), _T("95% Confidence Interval"), _T("99% Confidence Interval"), _T("Fastest Pass"), _T("Slowest Pass"), _T("Standard Deviation"), _T("Standard Error"), _T("Command"));
|
||||
_ftprintf_s(fLog, _T("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n"), _T("Program"), _T("Passes"), _T("Mean Time"), _T("90% Confidence Interval"), _T("95% Confidence Interval"), _T("99% Confidence Interval"), _T("Fastest Pass"), _T("Slowest Pass"), _T("Standard Deviation"), _T("Standard Error"), _T("Command Line"));
|
||||
}
|
||||
_ftprintf_s(fLog, _T("%s\t%d\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%s\n"), getFileNameOnly(programFile).c_str(), maxPasses, stats_mean, confidenceInterval_90, confidenceInterval_95, confidenceInterval_99, stats_fastest, stats_slowest, standardDeviation, standardError, commandLine.c_str());
|
||||
if(ferror(fLog) == 0)
|
||||
{
|
||||
_ftprintf(stderr, _T("Log file updated successfully.\n\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
_ftprintf(stderr, _T("Failed to append data to the specified log file:\n%s\n\n"), logFile.c_str());
|
||||
}
|
||||
fclose(fLog); fLog = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: Failed to append results to log file!\n" << std::endl;
|
||||
_ftprintf(stderr, _T("Failed to open the specified log file for writing:\n%s\n\n"), logFile.c_str());
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
@ -503,24 +552,24 @@ static int mainEx(int argc, _TCHAR* argv[])
|
||||
catch(std::exception &e)
|
||||
{
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "GURU MEDITATION: Unhandeled C++ Exception (" << e.what() << ')' << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
_exit(-1);
|
||||
}
|
||||
catch(std::exception *e)
|
||||
{
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "GURU MEDITATION: Unhandeled C++ Exception (" << e->what() << ')' << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
_exit(-1);
|
||||
} catch(...)
|
||||
{
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "\n===========================================================================" << std::endl;
|
||||
std::cerr << "\n===============================================================================" << std::endl;
|
||||
std::cerr << "GURU MEDITATION: Unhandeled C++ Exception (Unknown Exception Type)" << std::endl;
|
||||
std::cerr << "===========================================================================\n" << std::endl;
|
||||
std::cerr << "===============================================================================\n" << std::endl;
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user