1 /***************************************************************************
2 testqgsruntimeprofiler.cpp
3 --------------------------------------
4 Date : June 2020
5 Copyright : (C) 2020 by Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15 #include "qgstest.h"
16
17 #include "qgsapplication.h"
18 #include "qgsruntimeprofiler.h"
19
20 #include <QSignalSpy>
21
22 class TestQgsRuntimeProfiler: public QObject
23 {
24 Q_OBJECT
25 private slots:
26 void initTestCase();
27 void cleanupTestCase();
28 void testGroups();
29 void threading();
30
31 };
32
33
initTestCase()34 void TestQgsRuntimeProfiler::initTestCase()
35 {
36 //
37 // Runs once before any tests are run
38 //
39 // init QGIS's paths - true means that all path will be inited from prefix
40 QgsApplication::init();
41 QgsApplication::initQgis();
42 }
43
cleanupTestCase()44 void TestQgsRuntimeProfiler::cleanupTestCase()
45 {
46 QgsApplication::exitQgis();
47 }
48
testGroups()49 void TestQgsRuntimeProfiler::testGroups()
50 {
51 QgsRuntimeProfiler profiler;
52
53 QVERIFY( profiler.groups().isEmpty() );
54 QVERIFY( !profiler.groupIsActive( QStringLiteral( "xxx" ) ) );
55
56 QSignalSpy spy( &profiler, &QgsRuntimeProfiler::groupAdded );
57 profiler.start( QStringLiteral( "task 1" ), QStringLiteral( "group 1" ) );
58
59 QCOMPARE( profiler.groups().count(), 1 );
60 QVERIFY( profiler.groups().contains( QStringLiteral( "group 1" ) ) );
61 QCOMPARE( spy.count(), 1 );
62 QCOMPARE( spy.at( 0 ).at( 0 ).toString(), QStringLiteral( "group 1" ) );
63 QVERIFY( profiler.groupIsActive( QStringLiteral( "group 1" ) ) );
64
65 profiler.start( QStringLiteral( "task 2" ), QStringLiteral( "group 2" ) );
66
67 QCOMPARE( profiler.groups().count(), 2 );
68 QVERIFY( profiler.groups().contains( QStringLiteral( "group 1" ) ) );
69 QVERIFY( profiler.groups().contains( QStringLiteral( "group 2" ) ) );
70 QCOMPARE( spy.count(), 2 );
71 QCOMPARE( spy.at( 1 ).at( 0 ).toString(), QStringLiteral( "group 2" ) );
72 QVERIFY( profiler.groupIsActive( QStringLiteral( "group 2" ) ) );
73 QVERIFY( profiler.groupIsActive( QStringLiteral( "group 1" ) ) );
74
75 // sub task
76 profiler.start( QStringLiteral( "task 1a" ), QStringLiteral( "group 1" ) );
77 QCOMPARE( profiler.groups().count(), 2 );
78 QCOMPARE( spy.count(), 2 );
79
80 profiler.end( QStringLiteral( "group 1" ) );
81 QVERIFY( profiler.groupIsActive( QStringLiteral( "group 1" ) ) );
82 profiler.end( QStringLiteral( "group 2" ) );
83 QVERIFY( !profiler.groupIsActive( QStringLiteral( "group 2" ) ) );
84 profiler.end( QStringLiteral( "group 1" ) );
85 QVERIFY( !profiler.groupIsActive( QStringLiteral( "group 1" ) ) );
86
87 QCOMPARE( profiler.childGroups( QString(), QStringLiteral( "group 1" ) ), QStringList() << QStringLiteral( "task 1" ) );
88 QCOMPARE( profiler.childGroups( QStringLiteral( "task 1" ), QStringLiteral( "group 1" ) ), QStringList() << QStringLiteral( "task 1a" ) );
89 QCOMPARE( profiler.childGroups( QString(), QStringLiteral( "group 2" ) ), QStringList() << QStringLiteral( "task 2" ) );
90 }
91
92
93
94 class ProfileInThread : public QThread
95 {
96
97 public :
ProfileInThread(QgsRuntimeProfiler * mainProfiler)98 ProfileInThread( QgsRuntimeProfiler *mainProfiler )
99 : mMainProfiler( mainProfiler )
100 {}
101
run()102 void run() override
103 {
104 QgsScopedRuntimeProfile profile( QStringLiteral( "in thread" ), QStringLiteral( "bg" ) );
105 QVERIFY( mMainProfiler != QgsApplication::profiler() );
106 }
107
108 private:
109 QgsRuntimeProfiler *mMainProfiler = nullptr;
110
111
112 };
113
threading()114 void TestQgsRuntimeProfiler::threading()
115 {
116 // test that profiling which occurs in a background thread is bubbled up to the main thread runtime profiler
117 QgsApplication::profiler()->clear();
118 QCOMPARE( QgsApplication::profiler()->rowCount(), 0 );
119
120 QThread *thread = new ProfileInThread( QgsApplication::profiler() );
121 {
122 QgsScopedRuntimeProfile profile( QStringLiteral( "launch thread" ), QStringLiteral( "main" ) );
123
124 QSignalSpy spy( QgsApplication::profiler(), &QgsRuntimeProfiler::groupAdded );
125 thread->start();
126 thread->exit();
127
128 spy.wait();
129 QCOMPARE( spy.count(), 1 );
130 QCOMPARE( spy.at( 0 ).at( 0 ).toString(), QStringLiteral( "bg" ) );
131 }
132
133 QCOMPARE( QgsApplication::profiler()->rowCount(), 2 );
134 int row1 = QgsApplication::profiler()->data( QgsApplication::profiler()->index( 0, 0 ) ).toString() == QLatin1String( "launch thread" ) ? 0 : 1;
135 QCOMPARE( QgsApplication::profiler()->data( QgsApplication::profiler()->index( row1, 0 ) ).toString(), QStringLiteral( "launch thread" ) );
136 QCOMPARE( QgsApplication::profiler()->data( QgsApplication::profiler()->index( row1, 0 ), QgsRuntimeProfilerNode::Group ).toString(), QStringLiteral( "main" ) );
137 QCOMPARE( QgsApplication::profiler()->data( QgsApplication::profiler()->index( row1 == 0 ? 1 : 0, 0 ) ).toString(), QStringLiteral( "in thread" ) );
138 QCOMPARE( QgsApplication::profiler()->data( QgsApplication::profiler()->index( row1 == 0 ? 1 : 0, 0 ), QgsRuntimeProfilerNode::Group ).toString(), QStringLiteral( "bg" ) );
139 }
140
141
142 QGSTEST_MAIN( TestQgsRuntimeProfiler )
143 #include "testqgsruntimeprofiler.moc"
144