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 }