Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Create RAII QgsScopedRuntimeProfile class and Python context manager
to ease logging of runtime profiles.

Now it's possible to do:

    with QgsRuntimeProfiler.profile('My operation'):
      # do something

to automatically handle everything required to log the operation runtime
  • Loading branch information
nyalldawson committed May 18, 2020
1 parent 1b4dd48 commit a913a6a
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 5 deletions.
2 changes: 2 additions & 0 deletions python/core/__init__.py.in
Expand Up @@ -36,6 +36,7 @@ from .additions.qgsgeometry import _geometryNonZero, mapping_geometry
from .additions.qgssettings import _qgssettings_enum_value, _qgssettings_set_enum_value, _qgssettings_flag_value
from .additions.qgstaskwrapper import QgsTaskWrapper
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
from .additions.runtimeprofiler import ScopedRuntimeProfileContextManager
from .additions.validitycheck import check

# Injections into classes
Expand All @@ -47,6 +48,7 @@ QgsProcessingFeatureSourceDefinition.__repr__ = processing_source_repr
QgsProcessingOutputLayerDefinition.__repr__ = processing_output_layer_repr
QgsProject.blockDirtying = ProjectDirtyBlocker
QgsReadWriteContext.enterCategory = ReadWriteContextEnterCategory
QgsRuntimeProfiler.profile = ScopedRuntimeProfileContextManager
QgsSettings.enumValue = _qgssettings_enum_value
QgsSettings.setEnumValue = _qgssettings_set_enum_value
QgsSettings.flagValue = _qgssettings_flag_value
Expand Down
37 changes: 37 additions & 0 deletions python/core/auto_generated/qgsruntimeprofiler.sip.in
Expand Up @@ -81,6 +81,43 @@ The current total time collected in the profiler.

};


class QgsScopedRuntimeProfile
{
%Docstring

Scoped object for logging of the runtime for a single operation or group of operations.

This class automatically takes care of registering an operation in the :py:func:`QgsApplication.profiler()`
registry upon construction, and recording of the elapsed runtime upon destruction.

Python scripts should not use QgsScopedRuntimeProfile directly. Instead, use :py:func:`QgsRuntimeProfiler.profile()`
.. code-block:: python

with QgsRuntimeProfiler.profile('My operation'):
# do something

.. versionadded:: 3.14
%End

%TypeHeaderCode
#include "qgsruntimeprofiler.h"
%End
public:

QgsScopedRuntimeProfile( const QString &name );
%Docstring
Constructor for QgsScopedRuntimeProfile.

Automatically registers the operation in the QgsApplication.profiler() instance
and starts recording the run time of the operation.
%End

~QgsScopedRuntimeProfile();

};


/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
3 changes: 1 addition & 2 deletions src/app/qgisapp.cpp
Expand Up @@ -14979,9 +14979,8 @@ void QgisApp::endProfile()

void QgisApp::functionProfile( void ( QgisApp::*fnc )(), QgisApp *instance, const QString &name )
{
startProfile( name );
QgsScopedRuntimeProfile profile( name );
( instance->*fnc )();
endProfile();
}

void QgisApp::mapCanvas_keyPressed( QKeyEvent *e )
Expand Down
1 change: 1 addition & 0 deletions src/app/qgspluginregistry.cpp
Expand Up @@ -32,6 +32,7 @@
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgsmessagebar.h"
#include "qgsruntimeprofiler.h"

#ifdef WITH_BINDINGS
#include "qgspythonutils.h"
Expand Down
20 changes: 17 additions & 3 deletions src/core/qgsruntimeprofiler.cpp
Expand Up @@ -96,10 +96,24 @@ void QgsRuntimeProfiler::clear()
double QgsRuntimeProfiler::totalTime()
{
double total = 0;
QList<QPair<QString, double> >::const_iterator it = mProfileTimes.constBegin();
for ( ; it != mProfileTimes.constEnd(); ++it )
for ( auto it = mProfileTimes.constBegin(); it != mProfileTimes.constEnd(); ++it )
{
total += ( *it ).second;
total += it->second;
}
return total;
}


//
// QgsScopedRuntimeProfile
//

QgsScopedRuntimeProfile::QgsScopedRuntimeProfile( const QString &name )
{
QgsApplication::profiler()->start( name );
}

QgsScopedRuntimeProfile::~QgsScopedRuntimeProfile()
{
QgsApplication::profiler()->end();
}
37 changes: 37 additions & 0 deletions src/core/qgsruntimeprofiler.h
Expand Up @@ -95,4 +95,41 @@ class CORE_EXPORT QgsRuntimeProfiler
QList< QPair< QString, double > > mProfileTimes;
};


/**
* \ingroup core
*
* Scoped object for logging of the runtime for a single operation or group of operations.
*
* This class automatically takes care of registering an operation in the QgsApplication::profiler()
* registry upon construction, and recording of the elapsed runtime upon destruction.
*
* Python scripts should not use QgsScopedRuntimeProfile directly. Instead, use QgsRuntimeProfiler.profile()
* \code{.py}
* with QgsRuntimeProfiler.profile('My operation'):
* # do something
* \endcode
*
* \since QGIS 3.14
*/
class CORE_EXPORT QgsScopedRuntimeProfile
{
public:

/**
* Constructor for QgsScopedRuntimeProfile.
*
* Automatically registers the operation in the QgsApplication::profiler() instance
* and starts recording the run time of the operation.
*/
QgsScopedRuntimeProfile( const QString &name );

/**
* Records the final runtime of the operation in the profiler instance.
*/
~QgsScopedRuntimeProfile();

};


#endif // QGSRUNTIMEPROFILER_H

0 comments on commit a913a6a

Please sign in to comment.