2013-06-19 15:12:32 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** Copyright (C) 2013 Digia Plc
|
|
|
|
|
** All rights reserved.
|
|
|
|
|
** For any questions to Digia, please use contact form at http://qt.digia.com <http://qt.digia.com/>
|
2013-06-19 15:12:32 +02:00
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
|
2013-06-19 15:12:32 +02:00
|
|
|
**
|
2013-06-20 12:34:02 +02:00
|
|
|
** Licensees holding valid Qt Enterprise licenses may use this file in
|
|
|
|
|
** accordance with the Qt Enterprise License Agreement provided with the
|
2013-06-19 15:12:32 +02:00
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2013-06-20 12:34:02 +02:00
|
|
|
** a written agreement between you and Digia.
|
|
|
|
|
**
|
|
|
|
|
** If you have questions regarding the use of this file, please use
|
|
|
|
|
** contact form at http://qt.digia.com <http://qt.digia.com/>
|
2013-06-19 15:12:32 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "pixmapcachemodel.h"
|
|
|
|
|
#include "qmldebug/qmlprofilereventtypes.h"
|
|
|
|
|
#include "qmlprofiler/qmlprofilermodelmanager.h"
|
2013-12-04 18:53:45 +01:00
|
|
|
#include "qmlprofiler/sortedtimelinemodel.h"
|
2014-06-12 16:03:40 +02:00
|
|
|
#include "qmlprofiler/abstracttimelinemodel_p.h"
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
#include <QDebug>
|
2014-03-21 16:52:28 +01:00
|
|
|
#include <QSize>
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2013-06-24 14:17:43 +02:00
|
|
|
namespace QmlProfilerExtension {
|
2013-06-19 15:12:32 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2013-08-12 11:44:35 +02:00
|
|
|
using namespace QmlProfiler;
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
enum CacheState {
|
|
|
|
|
Uncached, // After loading started (or some other proof of existence) or after uncaching
|
|
|
|
|
ToBeCached, // After determining the pixmap is to be cached but before knowing its size
|
|
|
|
|
Cached, // After caching a pixmap or determining the size of a ToBeCached pixmap
|
|
|
|
|
Uncacheable, // If loading failed without ToBeCached or after a corrupt pixmap has been uncached
|
|
|
|
|
Corrupt // If after ToBeCached we learn that loading failed
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum LoadState {
|
|
|
|
|
Initial,
|
|
|
|
|
Loading,
|
|
|
|
|
Finished,
|
|
|
|
|
Error
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct PixmapState {
|
|
|
|
|
PixmapState(int width, int height, CacheState cache = Uncached) :
|
|
|
|
|
size(width, height), started(-1), loadState(Initial), cacheState(cache) {}
|
|
|
|
|
PixmapState(CacheState cache = Uncached) : started(-1), loadState(Initial), cacheState(cache) {}
|
|
|
|
|
QSize size;
|
|
|
|
|
int started;
|
|
|
|
|
LoadState loadState;
|
|
|
|
|
CacheState cacheState;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Pixmap {
|
|
|
|
|
Pixmap() {}
|
|
|
|
|
Pixmap(const QString &url) : url(url), sizes(1) {}
|
|
|
|
|
QString url;
|
|
|
|
|
QVector<PixmapState> sizes;
|
|
|
|
|
};
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
class PixmapCacheModel::PixmapCacheModelPrivate :
|
|
|
|
|
public SortedTimelineModel<PixmapCacheEvent,
|
2014-06-12 16:03:40 +02:00
|
|
|
AbstractTimelineModel::AbstractTimelineModelPrivate>
|
2014-02-14 16:34:22 +01:00
|
|
|
{
|
2013-06-19 15:12:32 +02:00
|
|
|
public:
|
2014-03-25 12:06:48 +01:00
|
|
|
void computeMaxCacheSize();
|
2013-06-19 15:12:32 +02:00
|
|
|
void resizeUnfinishedLoads();
|
|
|
|
|
void flattenLoads();
|
2014-03-21 16:52:28 +01:00
|
|
|
int updateCacheCount(int lastCacheSizeEvent, qint64 startTime, qint64 pixSize,
|
|
|
|
|
PixmapCacheEvent &newEvent);
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
QVector<Pixmap> pixmaps;
|
2013-06-19 15:12:32 +02:00
|
|
|
int collapsedRowCount;
|
2014-02-14 16:34:22 +01:00
|
|
|
void addVP(QVariantList &l, QString label, qint64 time) const;
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
qint64 maxCacheSize;
|
2014-02-14 16:34:22 +01:00
|
|
|
private:
|
|
|
|
|
Q_DECLARE_PUBLIC(PixmapCacheModel)
|
2013-06-19 15:12:32 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PixmapCacheModel::PixmapCacheModel(QObject *parent)
|
2014-06-12 16:03:40 +02:00
|
|
|
: AbstractTimelineModel(new PixmapCacheModelPrivate(),
|
2014-02-14 16:34:22 +01:00
|
|
|
QLatin1String("PixmapCacheTimeLineModel"),
|
2014-06-06 16:37:47 +02:00
|
|
|
QLatin1String("Pixmap Cache"), QmlDebug::PixmapCacheEvent,
|
|
|
|
|
QmlDebug::MaximumRangeType, parent)
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
d->collapsedRowCount = 1;
|
2014-03-25 12:06:48 +01:00
|
|
|
d->maxCacheSize = 1;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-12 13:27:41 +02:00
|
|
|
int PixmapCacheModel::rowCount() const
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
if (isEmpty())
|
|
|
|
|
return 1;
|
2014-02-14 16:34:22 +01:00
|
|
|
if (d->expanded)
|
2014-03-27 15:43:09 +01:00
|
|
|
return d->pixmaps.count() + 2;
|
2013-06-19 15:12:32 +02:00
|
|
|
return d->collapsedRowCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int PixmapCacheModel::getEventRow(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
|
|
|
|
if (d->expanded)
|
2014-03-27 15:43:09 +01:00
|
|
|
return getEventId(index) + 1;
|
2013-12-04 18:53:45 +01:00
|
|
|
return d->range(index).rowNumberCollapsed;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int PixmapCacheModel::getEventId(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2014-03-27 15:43:09 +01:00
|
|
|
return d->range(index).pixmapEventType == PixmapCacheCountChanged ?
|
|
|
|
|
0 : d->range(index).urlIndex + 1;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QColor PixmapCacheModel::getColor(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2013-12-04 18:53:45 +01:00
|
|
|
if (d->range(index).pixmapEventType == PixmapCacheCountChanged)
|
2014-02-26 17:44:58 +01:00
|
|
|
return getColorByHue(PixmapCacheCountHue);
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2014-02-26 17:44:58 +01:00
|
|
|
return getEventColor(index);
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float PixmapCacheModel::getHeight(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2014-03-21 13:28:54 +01:00
|
|
|
if (d->range(index).pixmapEventType == PixmapCacheCountChanged)
|
|
|
|
|
return 0.15 + (float)d->range(index).cacheSize * 0.85 / (float)d->maxCacheSize;
|
|
|
|
|
else
|
|
|
|
|
return 1.0f;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString getFilenameOnly(QString absUrl)
|
|
|
|
|
{
|
|
|
|
|
int characterPos = absUrl.lastIndexOf(QLatin1Char('/'))+1;
|
|
|
|
|
if (characterPos < absUrl.length())
|
|
|
|
|
absUrl = absUrl.mid(characterPos);
|
|
|
|
|
return absUrl;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 13:27:41 +02:00
|
|
|
const QVariantList PixmapCacheModel::getLabels() const
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
QVariantList result;
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
if (d->expanded && !isEmpty()) {
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
|
|
|
|
// Cache Size
|
|
|
|
|
QVariantMap element;
|
|
|
|
|
element.insert(QLatin1String("description"), QVariant(QLatin1String("Cache Size")));
|
|
|
|
|
|
|
|
|
|
element.insert(QLatin1String("id"), QVariant(0));
|
|
|
|
|
result << element;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
for (int i=0; i < d->pixmaps.count(); i++) {
|
2013-06-19 15:12:32 +02:00
|
|
|
// Loading
|
|
|
|
|
QVariantMap element;
|
2014-03-21 16:52:28 +01:00
|
|
|
element.insert(QLatin1String("description"),
|
|
|
|
|
QVariant(getFilenameOnly(d->pixmaps[i].url)));
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
element.insert(QLatin1String("id"), QVariant(i+1));
|
|
|
|
|
result << element;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
void PixmapCacheModel::PixmapCacheModelPrivate::addVP(QVariantList &l, QString label, qint64 time) const
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
|
|
|
|
if (time > 0) {
|
|
|
|
|
QVariantMap res;
|
2014-02-18 18:34:43 +01:00
|
|
|
res.insert(label, QVariant(QmlProfilerBaseModel::formatTime(time)));
|
2013-06-19 15:12:32 +02:00
|
|
|
l << res;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QVariantList PixmapCacheModel::getEventDetails(int index) const
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(const PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
QVariantList result;
|
2013-12-04 18:53:45 +01:00
|
|
|
const PixmapCacheModelPrivate::Range *ev = &d->range(index);
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QVariantMap res;
|
|
|
|
|
if (ev->pixmapEventType == PixmapCacheCountChanged)
|
|
|
|
|
res.insert(QLatin1String("title"), QVariant(QLatin1String("Image Cached")));
|
|
|
|
|
else if (ev->pixmapEventType == PixmapLoadingStarted)
|
|
|
|
|
res.insert(QLatin1String("title"), QVariant(QLatin1String("Image Loaded")));
|
|
|
|
|
result << res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ev->pixmapEventType != PixmapCacheCountChanged) {
|
|
|
|
|
d->addVP(result, tr("Duration"), ev->duration );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QVariantMap res;
|
2014-03-21 16:52:28 +01:00
|
|
|
res.insert(tr("File"), QVariant(getFilenameOnly(d->pixmaps[ev->urlIndex].url)));
|
2013-06-19 15:12:32 +02:00
|
|
|
result << res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
QVariantMap res;
|
2014-03-21 16:52:28 +01:00
|
|
|
res.insert(tr("Width"), QVariant(QString::fromLatin1("%1 px")
|
|
|
|
|
.arg(d->pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.width())));
|
2013-06-19 15:12:32 +02:00
|
|
|
result << res;
|
|
|
|
|
res.clear();
|
2014-03-21 16:52:28 +01:00
|
|
|
res.insert(tr("Height"), QVariant(QString::fromLatin1("%1 px")
|
|
|
|
|
.arg(d->pixmaps[ev->urlIndex].sizes[ev->sizeIndex].size.height())));
|
2013-06-19 15:12:32 +02:00
|
|
|
result << res;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
if (ev->pixmapEventType == PixmapLoadingStarted &&
|
|
|
|
|
d->pixmaps[ev->urlIndex].sizes[ev->sizeIndex].loadState != Finished) {
|
2013-06-19 15:12:32 +02:00
|
|
|
QVariantMap res;
|
|
|
|
|
res.insert(tr("Result"), QVariant(QLatin1String("Load Error")));
|
|
|
|
|
result << res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
/* Ultimately there is no way to know which cache entry a given event refers to as long as we only
|
|
|
|
|
* receive the pixmap URL from the application. Multiple copies of different sizes may be cached
|
|
|
|
|
* for each URL. However, we can apply some heuristics to make the result somewhat plausible by
|
|
|
|
|
* using the following assumptions:
|
|
|
|
|
*
|
|
|
|
|
* - PixmapSizeKnown will happen at most once for every cache entry.
|
|
|
|
|
* - PixmapSizeKnown cannot happen for entries with PixmapLoadingError and vice versa.
|
|
|
|
|
* - PixmapCacheCountChanged can happen for entries with PixmapLoadingError but doesn't have to.
|
|
|
|
|
* - Decreasing PixmapCacheCountChanged events can only happen for entries that have seen an
|
|
|
|
|
* increasing PixmapCacheCountChanged (but that may have happened before the trace).
|
|
|
|
|
* - PixmapCacheCountChanged can happen before or after PixmapSizeKnown.
|
|
|
|
|
* - For every PixmapLoadingFinished or PixmapLoadingError there is exactly one
|
|
|
|
|
* PixmapLoadingStarted event, but it may be before the trace.
|
|
|
|
|
* - For every PixmapLoadingStarted there is exactly one PixmapLoadingFinished or
|
|
|
|
|
* PixmapLoadingError, but it may be after the trace.
|
|
|
|
|
* - Decreasing PixmapCacheCountChanged events in the presence of corrupt cache entries are more
|
|
|
|
|
* likely to clear those entries than other, correctly loaded ones.
|
|
|
|
|
* - Increasing PixmapCacheCountChanged events are more likely to refer to correctly loaded entries
|
|
|
|
|
* than to ones with PixmapLoadingError.
|
|
|
|
|
* - PixmapLoadingFinished and PixmapLoadingError are more likely to refer to cache entries that
|
|
|
|
|
* have seen a PixmapLoadingStarted than to ones that haven't.
|
|
|
|
|
*
|
|
|
|
|
* For each URL we keep an ordered list of pixmaps possibly being loaded and assign new events to
|
|
|
|
|
* the first entry that "fits". If multiple sizes of the same pixmap are being loaded concurrently
|
|
|
|
|
* we generally assume that the PixmapLoadingFinished and PixmapLoadingError events occur in the
|
|
|
|
|
* order we learn about the existence of these sizes, subject to the above constraints. This is not
|
|
|
|
|
* necessarily the order the pixmaps are really loaded but it's the best we can do with the given
|
|
|
|
|
* information. If they're loaded sequentially the representation is correct.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-06-19 15:12:32 +02:00
|
|
|
void PixmapCacheModel::loadData()
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
clear();
|
2014-02-18 18:34:43 +01:00
|
|
|
QmlProfilerDataModel *simpleModel = d->modelManager->qmlModel();
|
2013-06-19 15:12:32 +02:00
|
|
|
if (simpleModel->isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int lastCacheSizeEvent = -1;
|
|
|
|
|
int cumulatedCount = 0;
|
|
|
|
|
|
2014-06-13 16:56:46 +02:00
|
|
|
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types = simpleModel->getEventTypes();
|
2014-02-18 18:34:43 +01:00
|
|
|
foreach (const QmlProfilerDataModel::QmlEventData &event, simpleModel->getEvents()) {
|
2014-06-13 16:56:46 +02:00
|
|
|
const QmlProfilerDataModel::QmlEventTypeData &type = types[event.typeIndex];
|
|
|
|
|
if (!eventAccepted(type))
|
2013-06-19 15:12:32 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
PixmapCacheEvent newEvent;
|
2014-06-13 16:56:46 +02:00
|
|
|
newEvent.pixmapEventType = type.detailType;
|
2013-12-04 18:53:45 +01:00
|
|
|
qint64 startTime = event.startTime;
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
newEvent.urlIndex = -1;
|
|
|
|
|
for (QVector<Pixmap>::const_iterator it(d->pixmaps.cend()); it != d->pixmaps.cbegin();) {
|
2014-06-13 16:56:46 +02:00
|
|
|
if ((--it)->url == type.location.filename) {
|
2014-03-21 16:52:28 +01:00
|
|
|
newEvent.urlIndex = it - d->pixmaps.cbegin();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newEvent.sizeIndex = -1;
|
2013-06-19 15:12:32 +02:00
|
|
|
if (newEvent.urlIndex == -1) {
|
2014-03-21 16:52:28 +01:00
|
|
|
newEvent.urlIndex = d->pixmaps.count();
|
2014-06-13 16:56:46 +02:00
|
|
|
d->pixmaps << Pixmap(type.location.filename);
|
2013-12-06 14:24:16 +01:00
|
|
|
}
|
|
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
Pixmap &pixmap = d->pixmaps[newEvent.urlIndex];
|
2013-12-02 14:26:49 +01:00
|
|
|
switch (newEvent.pixmapEventType) {
|
2014-03-21 16:52:28 +01:00
|
|
|
case PixmapSizeKnown: {// pixmap size
|
|
|
|
|
// Look for pixmaps for which we don't know the size, yet and which have actually been
|
|
|
|
|
// loaded.
|
|
|
|
|
for (QVector<PixmapState>::iterator i(pixmap.sizes.begin());
|
|
|
|
|
i != pixmap.sizes.end(); ++i) {
|
|
|
|
|
if (i->size.isValid() || i->cacheState == Uncacheable || i->cacheState == Corrupt)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// We can't have cached it before we knew the size
|
|
|
|
|
Q_ASSERT(i->cacheState != Cached);
|
|
|
|
|
|
|
|
|
|
i->size.setWidth(event.numericData1);
|
|
|
|
|
i->size.setHeight(event.numericData2);
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.begin();
|
2013-12-06 14:59:06 +01:00
|
|
|
break;
|
2014-03-21 16:52:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
newEvent.sizeIndex = pixmap.sizes.length();
|
|
|
|
|
pixmap.sizes << PixmapState(event.numericData1, event.numericData2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PixmapState &state = pixmap.sizes[newEvent.sizeIndex];
|
|
|
|
|
if (state.cacheState == ToBeCached) {
|
|
|
|
|
lastCacheSizeEvent = d->updateCacheCount(lastCacheSizeEvent, startTime,
|
|
|
|
|
state.size.width() * state.size.height(), newEvent);
|
|
|
|
|
state.cacheState = Cached;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-12-02 14:26:49 +01:00
|
|
|
case PixmapCacheCountChanged: {// Cache Size Changed Event
|
2013-12-04 18:53:45 +01:00
|
|
|
startTime = event.startTime + 1; // delay 1 ns for proper sorting
|
2014-03-21 16:52:28 +01:00
|
|
|
|
|
|
|
|
bool uncache = cumulatedCount > event.numericData3;
|
|
|
|
|
cumulatedCount = event.numericData3;
|
|
|
|
|
qint64 pixSize = 0;
|
|
|
|
|
|
|
|
|
|
// First try to find a preferred pixmap, which either is Corrupt and will be uncached
|
|
|
|
|
// or is uncached and will be cached.
|
|
|
|
|
for (QVector<PixmapState>::iterator i(pixmap.sizes.begin());
|
|
|
|
|
i != pixmap.sizes.end(); ++i) {
|
|
|
|
|
if (uncache && i->cacheState == Corrupt) {
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.begin();
|
|
|
|
|
i->cacheState = Uncacheable;
|
|
|
|
|
break;
|
|
|
|
|
} else if (!uncache && i->cacheState == Uncached) {
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.begin();
|
|
|
|
|
if (i->size.isValid()) {
|
|
|
|
|
pixSize = i->size.width() * i->size.height();
|
|
|
|
|
i->cacheState = Cached;
|
|
|
|
|
} else {
|
|
|
|
|
i->cacheState = ToBeCached;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If none found, check for cached or ToBeCached pixmaps that shall be uncached or
|
|
|
|
|
// Error pixmaps that become corrupt cache entries. We also accept Initial to be
|
|
|
|
|
// uncached as we may have missed the matching PixmapCacheCountChanged that cached it.
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
for (QVector<PixmapState>::iterator i(pixmap.sizes.begin());
|
|
|
|
|
i != pixmap.sizes.end(); ++i) {
|
|
|
|
|
if (uncache && (i->cacheState == Cached || i->cacheState == ToBeCached ||
|
|
|
|
|
i->cacheState == Uncached)) {
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.begin();
|
|
|
|
|
if (i->size.isValid())
|
|
|
|
|
pixSize = -i->size.width() * i->size.height();
|
|
|
|
|
i->cacheState = Uncached;
|
|
|
|
|
break;
|
|
|
|
|
} else if (!uncache && i->cacheState == Uncacheable) {
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.begin();
|
|
|
|
|
i->cacheState = Corrupt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-12-06 14:59:06 +01:00
|
|
|
}
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
2014-03-21 16:52:28 +01:00
|
|
|
|
|
|
|
|
// If that does't work, create a new entry.
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
newEvent.sizeIndex = pixmap.sizes.length();
|
|
|
|
|
pixmap.sizes << PixmapState(uncache ? Uncached : ToBeCached);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastCacheSizeEvent = d->updateCacheCount(lastCacheSizeEvent, startTime, pixSize,
|
|
|
|
|
newEvent);
|
2013-12-02 14:26:49 +01:00
|
|
|
break;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
2013-12-02 14:26:49 +01:00
|
|
|
case PixmapLoadingStarted: // Load
|
2014-03-21 16:52:28 +01:00
|
|
|
// Look for a pixmap that hasn't been started, yet. There may have been a refcount
|
|
|
|
|
// event, which we ignore.
|
|
|
|
|
for (QVector<PixmapState>::const_iterator i(pixmap.sizes.cbegin());
|
|
|
|
|
i != pixmap.sizes.cend(); ++i) {
|
|
|
|
|
if (i->loadState == Initial) {
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.cbegin();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
newEvent.sizeIndex = pixmap.sizes.length();
|
|
|
|
|
pixmap.sizes << PixmapState();
|
|
|
|
|
}
|
|
|
|
|
pixmap.sizes[newEvent.sizeIndex].started = d->insertStart(startTime, newEvent);
|
|
|
|
|
pixmap.sizes[newEvent.sizeIndex].loadState = Loading;
|
2013-12-02 14:26:49 +01:00
|
|
|
break;
|
|
|
|
|
case PixmapLoadingFinished:
|
|
|
|
|
case PixmapLoadingError: {
|
2014-03-21 16:52:28 +01:00
|
|
|
// First try to find one that has already started
|
|
|
|
|
for (QVector<PixmapState>::const_iterator i(pixmap.sizes.cbegin());
|
|
|
|
|
i != pixmap.sizes.cend(); ++i) {
|
|
|
|
|
if (i->loadState != Loading)
|
|
|
|
|
continue;
|
|
|
|
|
// Pixmaps with known size cannot be errors and vice versa
|
|
|
|
|
if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.cbegin();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If none was found use any other compatible one
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
for (QVector<PixmapState>::const_iterator i(pixmap.sizes.cbegin());
|
|
|
|
|
i != pixmap.sizes.cend(); ++i) {
|
|
|
|
|
if (i->loadState != Initial)
|
|
|
|
|
continue;
|
|
|
|
|
// Pixmaps with known size cannot be errors and vice versa
|
|
|
|
|
if (newEvent.pixmapEventType == PixmapLoadingError && i->size.isValid())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
newEvent.sizeIndex = i - pixmap.sizes.cbegin();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If again none was found, create one.
|
|
|
|
|
if (newEvent.sizeIndex == -1) {
|
|
|
|
|
newEvent.sizeIndex = pixmap.sizes.length();
|
|
|
|
|
pixmap.sizes << PixmapState();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PixmapState &state = pixmap.sizes[newEvent.sizeIndex];
|
|
|
|
|
// If the pixmap loading wasn't started, start it at traceStartTime()
|
|
|
|
|
if (state.loadState == Initial) {
|
2013-12-06 14:24:16 +01:00
|
|
|
newEvent.pixmapEventType = PixmapLoadingStarted;
|
2014-03-21 16:52:28 +01:00
|
|
|
state.started = d->insert(traceStartTime(), startTime - traceStartTime(), newEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d->insertEnd(state.started, startTime - d->range(state.started).start);
|
|
|
|
|
if (newEvent.pixmapEventType == PixmapLoadingError) {
|
|
|
|
|
state.loadState = Error;
|
|
|
|
|
switch (state.cacheState) {
|
|
|
|
|
case Uncached:
|
|
|
|
|
state.cacheState = Uncacheable;
|
|
|
|
|
break;
|
|
|
|
|
case ToBeCached:
|
|
|
|
|
state.cacheState = Corrupt;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Cached cannot happen as size would have to be known and Corrupt or
|
|
|
|
|
// Uncacheable cannot happen as we only accept one finish or error event per
|
|
|
|
|
// pixmap.
|
|
|
|
|
Q_ASSERT(false);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
state.loadState = Finished;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
2013-12-02 14:26:49 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2013-12-02 14:13:10 +01:00
|
|
|
}
|
2013-06-19 15:12:32 +02:00
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), 2*simpleModel->getEvents().count());
|
2013-12-06 14:24:16 +01:00
|
|
|
}
|
2013-12-02 14:13:10 +01:00
|
|
|
|
2013-06-19 15:12:32 +02:00
|
|
|
if (lastCacheSizeEvent != -1) {
|
2013-12-04 18:53:45 +01:00
|
|
|
d->insertEnd(lastCacheSizeEvent, traceEndTime() - d->range(lastCacheSizeEvent).start);
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d->resizeUnfinishedLoads();
|
|
|
|
|
|
2014-03-25 12:06:48 +01:00
|
|
|
d->computeMaxCacheSize();
|
2013-06-19 15:12:32 +02:00
|
|
|
d->flattenLoads();
|
2013-12-04 18:53:45 +01:00
|
|
|
d->computeNesting();
|
2013-07-25 17:29:22 +02:00
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PixmapCacheModel::clear()
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_D(PixmapCacheModel);
|
2014-04-09 16:33:00 +02:00
|
|
|
d->clear();
|
2014-03-21 16:52:28 +01:00
|
|
|
d->pixmaps.clear();
|
2013-06-19 15:12:32 +02:00
|
|
|
d->collapsedRowCount = 1;
|
2014-03-25 12:06:48 +01:00
|
|
|
d->maxCacheSize = 1;
|
2014-02-14 16:34:22 +01:00
|
|
|
d->expanded = false;
|
2013-07-25 17:29:22 +02:00
|
|
|
|
2014-02-14 16:34:22 +01:00
|
|
|
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
|
2014-03-25 12:06:48 +01:00
|
|
|
void PixmapCacheModel::PixmapCacheModelPrivate::computeMaxCacheSize()
|
2013-06-19 15:12:32 +02:00
|
|
|
{
|
2014-03-25 12:06:48 +01:00
|
|
|
maxCacheSize = 1;
|
2013-12-04 18:53:45 +01:00
|
|
|
foreach (const PixmapCacheModel::PixmapCacheEvent &event, ranges) {
|
2013-06-19 15:12:32 +02:00
|
|
|
if (event.pixmapEventType == PixmapCacheModel::PixmapCacheCountChanged) {
|
2014-03-25 12:06:48 +01:00
|
|
|
if (event.cacheSize > maxCacheSize)
|
2013-06-19 15:12:32 +02:00
|
|
|
maxCacheSize = event.cacheSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PixmapCacheModel::PixmapCacheModelPrivate::resizeUnfinishedLoads()
|
|
|
|
|
{
|
2014-02-14 16:34:22 +01:00
|
|
|
Q_Q(PixmapCacheModel);
|
2013-06-19 15:12:32 +02:00
|
|
|
// all the "load start" events with duration 0 continue till the end of the trace
|
2013-12-04 18:53:45 +01:00
|
|
|
for (int i = 0; i < count(); i++) {
|
|
|
|
|
if (range(i).pixmapEventType == PixmapCacheModel::PixmapLoadingStarted &&
|
|
|
|
|
range(i).duration == 0) {
|
|
|
|
|
insertEnd(i, q->traceEndTime() - range(i).start);
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PixmapCacheModel::PixmapCacheModelPrivate::flattenLoads()
|
|
|
|
|
{
|
2014-03-27 15:43:09 +01:00
|
|
|
collapsedRowCount = 0;
|
|
|
|
|
|
2013-06-19 15:12:32 +02:00
|
|
|
// computes "compressed row"
|
|
|
|
|
QVector <qint64> eventEndTimes;
|
2013-12-04 18:53:45 +01:00
|
|
|
for (int i = 0; i < count(); i++) {
|
|
|
|
|
PixmapCacheModel::PixmapCacheEvent &event = data(i);
|
|
|
|
|
const Range &start = range(i);
|
|
|
|
|
if (event.pixmapEventType == PixmapCacheModel::PixmapLoadingStarted) {
|
|
|
|
|
event.rowNumberCollapsed = 0;
|
|
|
|
|
while (eventEndTimes.count() > event.rowNumberCollapsed &&
|
|
|
|
|
eventEndTimes[event.rowNumberCollapsed] > start.start)
|
|
|
|
|
event.rowNumberCollapsed++;
|
|
|
|
|
|
|
|
|
|
if (eventEndTimes.count() == event.rowNumberCollapsed)
|
2013-06-19 15:12:32 +02:00
|
|
|
eventEndTimes << 0; // increase stack length, proper value added below
|
2013-12-04 18:53:45 +01:00
|
|
|
eventEndTimes[event.rowNumberCollapsed] = start.start + start.duration;
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
// readjust to account for category empty row and bargraph
|
2013-12-04 18:53:45 +01:00
|
|
|
event.rowNumberCollapsed += 2;
|
2013-06-19 15:12:32 +02:00
|
|
|
}
|
|
|
|
|
if (event.rowNumberCollapsed > collapsedRowCount)
|
|
|
|
|
collapsedRowCount = event.rowNumberCollapsed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Starting from 0, count is maxIndex+1
|
|
|
|
|
collapsedRowCount++;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-21 16:52:28 +01:00
|
|
|
int PixmapCacheModel::PixmapCacheModelPrivate::updateCacheCount(int lastCacheSizeEvent,
|
|
|
|
|
qint64 startTime, qint64 pixSize, PixmapCacheEvent &newEvent)
|
|
|
|
|
{
|
|
|
|
|
newEvent.pixmapEventType = PixmapCacheCountChanged;
|
|
|
|
|
newEvent.rowNumberCollapsed = 1;
|
|
|
|
|
|
|
|
|
|
qint64 prevSize = 0;
|
|
|
|
|
if (lastCacheSizeEvent != -1) {
|
|
|
|
|
prevSize = range(lastCacheSizeEvent).cacheSize;
|
|
|
|
|
insertEnd(lastCacheSizeEvent, startTime - range(lastCacheSizeEvent).start);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newEvent.cacheSize = prevSize + pixSize;
|
|
|
|
|
return insertStart(startTime, newEvent);
|
|
|
|
|
}
|
2013-06-19 15:12:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
2013-06-24 14:17:43 +02:00
|
|
|
} // namespace QmlProfilerExtension
|