File indexing completed on 2024-04-28 16:30:34
0001 /*************************************************************************** 0002 * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr 0003 * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 ***************************************************************************/ 0006 /** @file 0007 * This file implements classes SKGTraces. 0008 * 0009 * @author Stephane MANKOWSKI / Guillaume DE BURE 0010 */ 0011 #include "skgtraces.h" 0012 0013 #ifdef Q_OS_WIN 0014 #include <windows.h> 0015 #else 0016 #include <sys/time.h> 0017 #endif 0018 #include "skgerror.h" 0019 #include "skgservices.h" 0020 0021 /** 0022 * To generate a colorized string 0023 */ 0024 #define COLORED(TEXT) \ 0025 ("\x1b[3"%QString::number(1+(((SKGTraces::SKGIndentTrace.count()-2)/2)%7))%'m'%(TEXT)%"\x1b[39m") 0026 /** 0027 * To generate a red string 0028 */ 0029 #define COLOREDRED(TEXT) \ 0030 (QStringLiteral("\x1b[31m")%(TEXT)%"\x1b[39m") 0031 0032 // =================================================================== 0033 int SKGTraces::SKGLevelTrace = SKGServices::stringToInt(SKGServices::getEnvVariable(QStringLiteral("SKGTRACE"))); 0034 bool SKGTraces::SKGPerfo = !SKGServices::getEnvVariable(QStringLiteral("SKGTRACEPERFO")).isEmpty(); 0035 QString SKGTraces::SKGIndentTrace = QStringLiteral("##"); 0036 SKGPerfoMap SKGTraces::m_SKGPerfoMethode; 0037 SKGQStringStack SKGTraces::m_SKGPerfoPathMethode; 0038 QTextStream SKGTraces::SKGCout(stdout, QIODevice::WriteOnly); 0039 // =================================================================== 0040 SKGTraces::SKGTraces(int iLevel, const char* iName, SKGError* iRC) 0041 { 0042 init(iLevel, QLatin1String(iName), iRC); 0043 } 0044 0045 SKGTraces::SKGTraces(int iLevel, const QString& iName, SKGError* iRC) 0046 { 0047 init(iLevel, iName, iRC); 0048 } 0049 0050 void SKGTraces::init(int iLevel, const QString& iName, SKGError* iRC) 0051 { 0052 IFSKGTRACEL(iLevel) { 0053 m_mame = iName; 0054 m_output = true; 0055 0056 m_rc = iRC; 0057 SKGIndentTrace += QStringLiteral(" "); 0058 0059 SKGTRACE << COLORED('>' % m_mame) << SKGENDL; 0060 } else { 0061 m_rc = nullptr; 0062 m_output = false; 0063 } 0064 0065 if (SKGPerfo) { 0066 m_profiling = true; 0067 m_mame = iName; 0068 0069 // Push the method in the stack 0070 SKGTraces::m_SKGPerfoPathMethode.push(m_mame); 0071 0072 // Pour les mesures de perfos 0073 #ifdef Q_OS_WIN 0074 m_elapse = static_cast<double>(GetTickCount()); 0075 #else 0076 struct timeval tv {}; 0077 struct timezone tz {}; 0078 gettimeofday(&tv, &tz); 0079 m_elapse = (static_cast<double>(1000.0 * tv.tv_sec)) + (static_cast<double>(tv.tv_usec / 1000.0)); 0080 #endif 0081 0082 // Searching the key in the map 0083 m_it = SKGTraces::m_SKGPerfoMethode.find(m_mame); 0084 if (m_it == SKGTraces::m_SKGPerfoMethode.end()) { 0085 // Not found ==> initialisation 0086 SKGPerfoInfo init{}; 0087 init.NbCall = 0; 0088 init.Time = 0; 0089 init.TimePropre = 0; 0090 init.TimeMin = 99999999; 0091 init.TimeMax = -1; 0092 0093 // Add the line 0094 SKGTraces::m_SKGPerfoMethode[m_mame] = init; 0095 0096 // find again 0097 m_it = SKGTraces::m_SKGPerfoMethode.find(m_mame); 0098 } 0099 } else { 0100 m_profiling = false; 0101 m_elapse = -1; 0102 } 0103 } 0104 0105 SKGTraces::~SKGTraces() 0106 { 0107 // Get delta time 0108 if (m_elapse >= 0) { 0109 #ifdef Q_OS_WIN 0110 m_elapse = static_cast<double>(GetTickCount()); 0111 #else 0112 struct timeval tv {}; 0113 struct timezone tz {}; 0114 gettimeofday(&tv, &tz); 0115 m_elapse = (static_cast<double>(1000.0 * tv.tv_sec)) + (static_cast<double>(tv.tv_usec / 1000.0)) - m_elapse; 0116 #endif 0117 } 0118 0119 if (m_output) { 0120 SKGTRACESUITE << SKGTraces::SKGIndentTrace << COLORED('<' % m_mame); 0121 if (m_rc != nullptr) { 0122 SKGTRACESUITE << (m_rc->isSucceeded() ? QString(COLORED(" RC=" % m_rc->getFullMessage())) : QString(COLOREDRED(" RC=" % m_rc->getFullMessage()))); 0123 } 0124 if (m_profiling) { 0125 SKGTRACESUITE << QStringLiteral(" TIME=") << m_elapse << QStringLiteral(" ms"); 0126 } 0127 SKGTRACESUITE << SKGENDL; 0128 SKGIndentTrace.resize(SKGIndentTrace.length() - 2); 0129 0130 m_rc = nullptr; 0131 } 0132 0133 if (m_profiling) { 0134 // Update values 0135 ++(m_it.value().NbCall); 0136 m_it.value().Time += m_elapse; 0137 m_it.value().TimePropre += m_elapse; 0138 if (m_elapse > m_it.value().TimeMax) { 0139 m_it.value().TimeMax = m_elapse; 0140 } 0141 if (m_elapse < m_it.value().TimeMin) { 0142 m_it.value().TimeMin = m_elapse; 0143 } 0144 0145 if (!SKGTraces::m_SKGPerfoPathMethode.empty() && SKGTraces::m_SKGPerfoPathMethode.top() == m_mame) { 0146 // Remove current method from stack 0147 SKGTraces::m_SKGPerfoPathMethode.pop(); 0148 0149 // Get previous method name 0150 if (!SKGTraces::m_SKGPerfoPathMethode.empty()) { 0151 QString previousMethode = qAsConst(SKGTraces::m_SKGPerfoPathMethode).top(); 0152 0153 // Searching the key in the map 0154 m_it = SKGTraces::m_SKGPerfoMethode.find(previousMethode); 0155 if (m_it != SKGTraces::m_SKGPerfoMethode.end()) { 0156 m_it.value().TimePropre -= m_elapse; 0157 } 0158 } 0159 } 0160 } 0161 } 0162 0163 void SKGTraces::cleanProfilingStatistics() 0164 { 0165 SKGTraces::m_SKGPerfoMethode.clear(); 0166 } 0167 0168 void SKGTraces::dumpProfilingStatistics() 0169 { 0170 QStringList dump = getProfilingStatistics(); 0171 0172 int nbl = dump.count(); 0173 for (int i = 0; i < nbl; ++i) { 0174 SKGTRACE << dump.at(i) << SKGENDL; 0175 } 0176 } 0177 0178 QStringList SKGTraces::getProfilingStatistics() 0179 { 0180 QStringList output; 0181 if (SKGPerfo) { 0182 output.push_back(QStringLiteral("method ; nb call ; millisecondes ; average ; min ; max ; own time ; average own time")); 0183 0184 SKGPerfoMap SKGPerfoMethodeCopy = m_SKGPerfoMethode; 0185 while (!SKGPerfoMethodeCopy.empty()) { 0186 // Recheche du temps propre maximal 0187 double maxtime = -1; 0188 SKGPerfoMapIterator max; 0189 SKGPerfoMapIterator it2; 0190 for (it2 = SKGPerfoMethodeCopy.begin() ; it2 != SKGPerfoMethodeCopy.end(); ++it2) { 0191 if (it2.value().TimePropre > maxtime || maxtime == -1) { 0192 maxtime = it2.value().TimePropre; 0193 max = it2; 0194 } 0195 } 0196 0197 // dump max 0198 if (maxtime != -1) { 0199 output.push_back(max.key() 0200 % " ; " % SKGServices::intToString(max.value().NbCall) 0201 % " ; " % SKGServices::doubleToString(max.value().Time) 0202 % " ; " % SKGServices::doubleToString((max.value().Time) / (static_cast<double>(max.value().NbCall))) 0203 % " ; " % SKGServices::doubleToString(max.value().TimeMin) 0204 % " ; " % SKGServices::doubleToString(max.value().TimeMax) 0205 % " ; " % SKGServices::doubleToString(max.value().TimePropre) 0206 % " ; " % SKGServices::doubleToString((max.value().TimePropre) / (static_cast<double>(max.value().NbCall)))); 0207 0208 // Remove it 0209 SKGPerfoMethodeCopy.erase(max); 0210 } 0211 } 0212 } 0213 0214 return output; 0215 }