pianobooster/src/Util.cpp

333 lines
7.7 KiB
C++

/*********************************************************************************/
/*!
@file Util.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2013, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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 3 of the License, or
(at your option) any later version.
PianoBooster 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 PianoBooster. If not, see <http://www.gnu.org/licenses/>.
*/
/*********************************************************************************/
#include <fstream>
#include <sstream>
#include <QCoreApplication>
#include <QDir>
#include <QElapsedTimer>
#include <QFile>
#include <QTime>
#include <QStringBuilder>
#include "Util.h"
#include "Cfg.h"
static FILE * logInfoFile = nullptr;
static FILE * logErrorFile = nullptr;
static bool logsOpened = false;
static void openLogFile() {
if (logsOpened == true)
return;
if (Cfg::useLogFile)
{
logInfoFile = fopen ("pb.log","w");
logErrorFile = logInfoFile;
if (logErrorFile == nullptr)
{
fputs("FATAL: cannot open the logfile", stderr);
exit(EXIT_FAILURE);
}
else
{
logsOpened = true;
}
}
else
{
logInfoFile = stdout;
logErrorFile = stderr;
}
}
static void flushLogs()
{
if (logInfoFile && logsOpened)
{
fflush(logInfoFile);
// logErrorFile is the same as logInfoFile
}
}
void closeLogs()
{
if (logInfoFile && logInfoFile != stdout)
{
fclose(logInfoFile);
logInfoFile = stdout;
logErrorFile = stdout;
}
}
/* prints an error message to stderr, and dies */
void fatal(const char *msg, ...)
{
va_list ap;
openLogFile();
fputs("FATAL: ", logErrorFile);
va_start(ap, msg);
vfprintf(logErrorFile, msg, ap);
va_end(ap);
fputc('\n', logErrorFile);
exit(EXIT_FAILURE);
}
void ppLog(logLevel_t level, const char *msg, ...)
{
va_list ap;
if (Cfg::logLevel < level)
return;
openLogFile();
va_start(ap, msg);
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
}
void ppLogInfo(const char *msg, ...)
{
va_list ap;
//fixme should call ppLog
if (Cfg::logLevel < LOG_LEVEL_INFO)
return;
openLogFile();
fputs("Info: ", logInfoFile);
va_start(ap, msg);
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
}
void ppLogWarn(const char *msg, ...)
{
va_list ap;
if (Cfg::logLevel < LOG_LEVEL_WARN)
return;
openLogFile();
fputs("Warn: ", logInfoFile);
va_start(ap, msg);
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
}
void ppLogTrace(const char *msg, ...)
{
#ifdef DEBUG_LOG_TRACE
va_list ap;
openLogFile();
fputs("Trace: ", logInfoFile);
va_start(ap, msg);
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
#else
Q_UNUSED(msg)
#endif
}
void ppLogDebug( const char *msg, ...)
{
va_list ap;
if (Cfg::logLevel < LOG_LEVEL_DEBUG)
return;
openLogFile();
fputs("Debug: ", logInfoFile);
va_start(ap, msg);
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
}
void ppLogError(const char *msg, ...)
{
va_list ap;
openLogFile();
fputs("ERROR: ", logErrorFile);
va_start(ap, msg);
vfprintf(logErrorFile, msg, ap);
va_end(ap);
fputc('\n', logErrorFile);
flushLogs();
}
#ifdef DEBUG_LOG_TIMING
static QTime s_realtime;
#endif
void ppTiming(const char *msg, ...)
{
#ifdef DEBUG_LOG_TIMING
va_list ap;
openLogFile();
va_start(ap, msg);
fprintf(logInfoFile, "Time %4d " , s_realtime.restart() );
vfprintf(logInfoFile, msg, ap);
va_end(ap);
fputc('\n', logInfoFile);
flushLogs();
#else
Q_UNUSED(msg)
#endif
}
////////////////////// BENCH MARK //////////////////////
static QElapsedTimer s_benchMarkTime;
static qint64 s_previousTime;
static qint64 s_previousFrameTime;
typedef struct
{
qint64 time;
QString msg;
qint64 deltaTotal;
qint64 deltaCount;
qint64 maxDelta;
qint64 minDelta;
qint64 frameRatePrevious;
qint64 frameRateCurrent;
} benchData_t;
benchData_t s_benchData[20];
benchData_t s_frameRate;
void benchMarkReset(benchData_t *pBench)
{
pBench->deltaTotal = 0;
pBench->deltaCount = 0;
pBench->maxDelta = 0;
pBench->minDelta = 9999999;
pBench->frameRatePrevious = pBench->frameRateCurrent;
}
void benchMarkInit()
{
s_benchMarkTime.start();
s_previousTime = 0;
s_previousFrameTime = 0;
for (int i=0; i < arraySize( s_benchData ); i++)
benchMarkReset(&s_benchData[i]);
benchMarkReset(&s_frameRate);
s_frameRate.msg = " *** Frame Rate ***";
}
static qint64 benchMarkUpdate(benchData_t *pBench, qint64 previousTime)
{
auto time = s_benchMarkTime.elapsed();
auto delta = time - previousTime;
pBench->deltaTotal += delta;
pBench->deltaCount++;
pBench->frameRateCurrent = time;
pBench->maxDelta = qMax(pBench->maxDelta, delta);
pBench->minDelta = qMin(pBench->minDelta, delta);
return time;
}
void benchMark(unsigned int id, const QString &message)
{
if (id >= arraySizeAs<unsigned int>(s_benchData))
return;
if (s_benchData[id].msg.size() == 0 )
s_benchData[id].msg = message;
s_previousTime = benchMarkUpdate(&s_benchData[id], s_previousTime);
}
void printResult(int i, benchData_t *pBench)
{
if (pBench->deltaCount == 0)
return;
openLogFile();
if (i>=0)
fprintf(logInfoFile, "Bench%2d: ", i);
else
fputs("Bench : ", logInfoFile);
fprintf(logInfoFile, "ct %4lld, min %2lld, avg %4.3f, max %2lld frame %4.3f %s\n", pBench->deltaCount, pBench->minDelta,
static_cast<double>(pBench->deltaTotal)/static_cast<double>(pBench->deltaCount),
pBench->maxDelta,
(static_cast<double>(pBench->frameRateCurrent - pBench->frameRatePrevious))/static_cast<double>(pBench->deltaCount),
qPrintable(pBench->msg));
benchMarkReset(pBench);
flushLogs();
}
void benchMarkResults()
{
const auto ticks = s_benchMarkTime.elapsed();
if ( (ticks - s_previousFrameTime) < 5000)
return;
s_previousFrameTime = ticks;
for (int i=0; i < arraySize(s_benchData); i++)
{
printResult(i, &s_benchData[i]);
}
}
// Returns the location where the data is stored
QString Util::dataDir(const QString &subDir) {
const auto appDirPath = QCoreApplication::applicationDirPath();
if (const auto nextToBin = QString(appDirPath % QChar('/') % subDir); QFile::exists(nextToBin)) {
return nextToBin;
}
if (const auto builtIn = QStringLiteral(":/") + subDir; QFile::exists(builtIn)) {
return builtIn;
}
#ifdef Q_OS_DARWIN
return appDirPath % QStringLiteral("/../Resources/") % subDir;
#else
return appDirPath % (QDir(appDirPath).dirName() == QLatin1String("bin")
? QStringLiteral("/../" DATA_DIR "/")
: QStringLiteral("/" DATA_DIR "/")) % subDir;
#endif
}