diff --git a/app/inputhelp.cpp b/app/inputhelp.cpp index c1f17036a..2f065b065 100644 --- a/app/inputhelp.cpp +++ b/app/inputhelp.cpp @@ -200,9 +200,14 @@ QVector InputHelp::logHeader( bool isHtml ) { retLines.push_back( QStringLiteral( "%1Mergin User Profile not available. To include it, open you Profile Page in InputApp%2" ).arg( isHtml ? "" : "" ).arg( isHtml ? "" : "" ) ); } + retLines.push_back( QStringLiteral( "------------------------------------------" ) ); retLines.push_back( QStringLiteral( "Screen Info:" ) ); retLines.append( InputUtils().dumpScreenInfo().split( "\n" ).toVector() ); retLines.push_back( QStringLiteral( "------------------------------------------" ) ); + retLines.push_back( QStringLiteral( "Profiler Data:" ) ); + retLines.append( InputUtils().qgisProfilerLog() ); + retLines.push_back( QStringLiteral( "------------------------------------------" ) ); + return retLines; } diff --git a/app/inpututils.cpp b/app/inpututils.cpp index c5504c7ec..48a295773 100644 --- a/app/inpututils.cpp +++ b/app/inpututils.cpp @@ -13,6 +13,7 @@ #include #include +#include "qgsruntimeprofiler.h" #include "qcoreapplication.h" #include "qgsgeometrycollection.h" #include "qgslinestring.h" @@ -1838,7 +1839,6 @@ bool InputUtils::rescaleImage( const QString &path, QgsProject *activeProject ) return ImageUtils::rescale( path, quality ); } - QgsGeometry InputUtils::createGeometryForLayer( QgsVectorLayer *layer ) { QgsGeometry geometry; @@ -1918,7 +1918,6 @@ QgsGeometry InputUtils::createGeometryForLayer( QgsVectorLayer *layer ) return geometry; } - QString InputUtils::invalidGeometryWarning( QgsVectorLayer *layer ) { QString msg; @@ -1999,6 +1998,59 @@ QString InputUtils::layerAttribution( QgsMapLayer *layer ) return QString(); } +const double PROFILER_THRESHOLD = 0.001; +static double qgsRuntimeProfilerExtractModelAsText( QStringList &lines, const QString &group, const QModelIndex &parent, int level ) +{ + double total_elapsed = 0.0; + + const int rc = QgsApplication::profiler()->rowCount( parent ); + for ( int r = 0; r < rc; r++ ) + { + QModelIndex rowIndex = QgsApplication::profiler()->index( r, 0, parent ); + if ( QgsApplication::profiler()->data( rowIndex, QgsRuntimeProfilerNode::Group ).toString() != group ) + continue; + bool ok; + double elapsed = QgsApplication::profiler()->data( rowIndex, QgsRuntimeProfilerNode::Elapsed ).toDouble( &ok ); + if ( !ok ) + elapsed = 0.0; + total_elapsed += elapsed; + + if ( elapsed > PROFILER_THRESHOLD ) + { + QString name = QgsApplication::profiler()->data( rowIndex, QgsRuntimeProfilerNode::Name ).toString(); + lines << QStringLiteral( " %1 %2: %3 sec" ).arg( QStringLiteral( ">" ).repeated( level + 1 ), name, QString::number( elapsed, 'f', 3 ) ); + } + total_elapsed += qgsRuntimeProfilerExtractModelAsText( lines, group, rowIndex, level + 1 ); + } + return total_elapsed; +} + +QVector InputUtils::qgisProfilerLog() +{ + QVector lines; + const QString project = QgsProject::instance()->fileName(); + + if ( !project.isEmpty() ) + { + lines << QStringLiteral( "QgsProject filename: %1" ).arg( project ); + } + + lines << QStringLiteral( "List of QgsRuntimeProfiler events above %1 sec" ).arg( QString::number( PROFILER_THRESHOLD, 'f', 3 ) ); + + const auto groups = QgsApplication::profiler()->groups(); + for ( const QString &g : groups ) + { + QVector groupLines; + double elapsed = qgsRuntimeProfilerExtractModelAsText( groupLines, g, QModelIndex(), 0 ); + if ( elapsed > PROFILER_THRESHOLD ) + { + lines << QStringLiteral( " %1: total %2 sec" ).arg( g, QString::number( elapsed, 'f', 3 ) ); + lines << groupLines; + } + } + return lines; +} + QList InputUtils::parsePositionUpdates( const QString &data ) { QList parsedUpdates; diff --git a/app/inpututils.h b/app/inpututils.h index 91aba22b3..78a9d1001 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -299,7 +299,6 @@ class InputUtils: public QObject */ Q_INVOKABLE static QString resolvePrefixForRelativePath( int relativeStorageMode, const QString &homePath, const QString &targetDir ); - /** * Returns absolute path of the file for given path and its prefix. If prefixPath is empty, * returns given path. @@ -412,7 +411,6 @@ class InputUtils: public QObject */ Q_INVOKABLE static QString evaluateExpression( const FeatureLayerPair &pair, QgsProject *activeProject, const QString &expression ); - /** * Returns the QVariant typeName of a \a field. * This is a stable identifier (compared to the provider field name). @@ -532,6 +530,11 @@ class InputUtils: public QObject */ Q_INVOKABLE static QString layerAttribution( QgsMapLayer *layer ); + /** + * Returns QGIS profiler data + */ + static QVector qgisProfilerLog(); + signals: Q_INVOKABLE void showNotificationRequested( const QString &message );