1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dparticlesystemlogging_p.h"
5#include <float.h> // FLT_MAX
6
7QT_BEGIN_NAMESPACE
8
9/*!
10 \qmltype ParticleSystem3DLogging
11 \inherits QtObject
12 \inqmlmodule QtQuick3D.Particles3D
13 \brief Provides information of the particle system.
14 \since 6.2
15
16 The \c ParticleSystem3DLogging type provides information about particle system statistics.
17 This element cannot be created directly, but can be retrieved from a \l ParticleSystem3D.
18*/
19
20QQuick3DParticleSystemLogging::QQuick3DParticleSystemLogging(QObject *parent)
21 : QObject(parent)
22{
23}
24
25/*!
26 \qmlproperty int ParticleSystem3DLogging::loggingInterval
27
28 This property defines in milliseconds how often the logging data is updated.
29 Longer update time increases the accuracy of \l {ParticleSystem3DLogging::time}{time} and
30 \l {ParticleSystem3DLogging::timeAverage}{timeAverage}, while shorter update times keep
31 the data more up to date.
32
33 The default value is \c 1000.
34*/
35
36int QQuick3DParticleSystemLogging::loggingInterval() const
37{
38 return m_loggingInterval;
39}
40
41void QQuick3DParticleSystemLogging::setLoggingInterval(int interval)
42{
43 if (m_loggingInterval == interval)
44 return;
45
46 m_loggingInterval = interval;
47 Q_EMIT loggingIntervalChanged();
48}
49
50/*!
51 \qmlproperty int ParticleSystem3DLogging::updates
52 \readonly
53
54 This property holds the amount of particle system updates since the last logging.
55 When \a loggingInterval is 1000 (default), this can be considered to match the fps.
56*/
57int QQuick3DParticleSystemLogging::updates() const
58{
59 return m_updates;
60}
61
62/*!
63 \qmlproperty int ParticleSystem3DLogging::particlesMax
64 \readonly
65
66 This property holds the maximum amount of particles in this system.
67 Maximum amount is the sum of system particles \l {Particle3D::maxAmount}{maxAmount} properties.
68*/
69int QQuick3DParticleSystemLogging::particlesMax() const
70{
71 return m_particlesMax;
72}
73
74/*!
75 \qmlproperty int ParticleSystem3DLogging::particlesUsed
76 \readonly
77
78 This property holds the amount of particles currently in use in this system.
79 This value should be close to \l particlesMax at some point of particle system
80 animation. If it is much smaller, consider decreasing \l {Particle3D::maxAmount}{maxAmount} values.
81 If it reaches \l particlesMax, particles are used effectively but it can also mean that
82 particles are reused before they reach the end of their \l {ParticleEmitter3D::lifeSpan}{lifeSpan}.
83 In this case, consider increasing the \l {Particle3D::maxAmount}{maxAmount} values.
84*/
85int QQuick3DParticleSystemLogging::particlesUsed() const
86{
87 return m_particlesUsed;
88}
89
90/*!
91 \qmlproperty real ParticleSystem3DLogging::time
92 \readonly
93
94 This property holds the time in milliseconds used for emitting and animating particles
95 in each frame.
96*/
97float QQuick3DParticleSystemLogging::time() const
98{
99 return m_time;
100}
101
102/*!
103 \qmlproperty real ParticleSystem3DLogging::timeAverage
104 \readonly
105
106 This property holds the average time in milliseconds used for emitting and animating
107 particles in each frame. Average is calculated from the middle 50% of the past
108 max 100 logging updates. So when \l loggingInterval is 1000, this represents an
109 average \l time in past 100 seconds. This can be used for measuring the performance
110 of current particle system.
111*/
112float QQuick3DParticleSystemLogging::timeAverage() const
113{
114 return m_timeAverage;
115}
116
117/*!
118 \qmlproperty real ParticleSystem3DLogging::timeDeviation
119 \since 6.3
120 \readonly
121
122 This property holds the deviation of the average times in milliseconds.
123 The value is the difference between maximum and minimum values of middle 50%
124 of the results, also called interquartile range (IQR).
125 Bigger deviation means that the times fluctuate more so \l timeAverage
126 can be considered to be less accurate.
127*/
128float QQuick3DParticleSystemLogging::timeDeviation() const
129{
130 return m_timeDeviation;
131}
132
133void QQuick3DParticleSystemLogging::updateTimes(qint64 time)
134{
135 m_time = float(time / 1000000.0) / m_updates;
136
137 m_totalTimesList.append(t: m_time);
138
139 // Keep max amount of times stored and remove the oldest values
140 const int MAX_TIMES = 100;
141 if (m_totalTimesList.size() > MAX_TIMES)
142 m_totalTimesList.removeFirst();
143
144 auto sortedTimes = m_totalTimesList;
145 std::sort(first: sortedTimes.begin(), last: sortedTimes.end());
146
147 // Calculate average from stored times.
148 // Only take into account the middle 50% of the values.
149 // This gives us interquartile range (IQR) and the average time among IQR.
150 if (sortedTimes.size() > 5) {
151 // Skip 25%, count 50%, so maxItem at 75%
152 const int skipAmount = roundf(x: 0.25f * float(sortedTimes.size()));
153 const int maxItem = sortedTimes.size() - skipAmount;
154 int countAmount = 0;
155 double totalTime = 0.0;
156 float maxTime = 0.0f;
157 float minTime = FLT_MAX;
158 for (int i = skipAmount; i < maxItem; i++) {
159 const float time = sortedTimes.at(i);
160 totalTime += time;
161 minTime = std::min(a: minTime, b: time);
162 maxTime = std::max(a: maxTime, b: time);
163 countAmount++;
164 }
165 m_timeAverage = float(totalTime / countAmount);
166 m_timeDeviation = maxTime - minTime;
167 Q_EMIT timeAverageChanged();
168 Q_EMIT timeDeviationChanged();
169 }
170 Q_EMIT timeChanged();
171}
172
173void QQuick3DParticleSystemLogging::resetData()
174{
175 m_updates = 0;
176 m_particlesMax = 0;
177 m_particlesUsed = 0;
178 m_time = 0.0f;
179 m_timeAverage = 0.0f;
180 m_timeDeviation = 0.0f;
181 m_totalTimesList.clear();
182 Q_EMIT updatesChanged();
183 Q_EMIT particlesMaxChanged();
184 Q_EMIT particlesUsedChanged();
185 Q_EMIT timeChanged();
186 Q_EMIT timeAverageChanged();
187 Q_EMIT timeDeviationChanged();
188}
189
190QT_END_NAMESPACE
191

source code of qtquick3d/src/quick3dparticles/qquick3dparticlesystemlogging.cpp