Rename QmlProfilerExtended to QmlProfilerExtension

Change-Id: I90325b264e2a41e9b52d7953c6e96e13c938705a
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
Kai Koehne
2013-06-24 14:17:43 +02:00
parent f86e2a4f72
commit 67d66abf8f
13 changed files with 69 additions and 69 deletions

View File

@@ -0,0 +1,13 @@
<plugin name=\"QmlProfilerExtension\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
<vendor>Digia Plc</vendor>
<copyright>(C) 2013 Digia Plc</copyright>
<license>
Commercial Usage
Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and Digia.
</license>
<category>Qt Quick</category>
<description>Qml Profiler Extension Plugin</description>
<url>http://www.qt-project.org</url>
$$dependencyList
</plugin>

View File

@@ -0,0 +1,542 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#include "pixmapcachemodel.h"
#include "qmldebug/qmlprofilereventtypes.h"
#include "qmlprofiler/qmlprofilermodelmanager.h"
#include <QDebug>
namespace QmlProfilerExtension {
namespace Internal {
using namespace QmlProfiler::Internal;
class PixmapCacheModel::PixmapCacheModelPrivate {
public:
PixmapCacheModelPrivate(PixmapCacheModel *qq):q(qq) {}
~PixmapCacheModelPrivate();
PixmapCacheModel *q;
void computeCacheSizes();
void resizeUnfinishedLoads();
void flattenLoads();
void computeRowCounts();
QVector < PixmapCacheModel::PixmapCacheEvent > eventList;
QVector < QString > pixmapUrls;
QVector < QPair<int, int> > pixmapSizes;
bool isExpanded;
int expandedRowCount;
int collapsedRowCount;
QString displayTime(double time);
void addVP(QVariantList &l, QString label, qint64 time);
qint64 minCacheSize;
qint64 maxCacheSize;
};
PixmapCacheModel::PixmapCacheModel(QObject *parent)
: AbstractTimelineModel(parent), d(new PixmapCacheModelPrivate(this))
{
d->collapsedRowCount = 1;
d->expandedRowCount = 1;
}
PixmapCacheModel::~PixmapCacheModel()
{
}
int PixmapCacheModel::categories() const
{
return 1;
}
QStringList PixmapCacheModel::categoryTitles() const
{
QStringList retString;
retString << categoryLabel(0);
return retString;
}
QString PixmapCacheModel::name() const
{
return QLatin1String("PixmapCacheTimeLineModel");
}
int PixmapCacheModel::count() const
{
return d->eventList.count();
}
bool PixmapCacheModel::isEmpty() const
{
return d->eventList.isEmpty();
}
bool PixmapCacheModel::eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const
{
return (event.eventType == QmlDebug::PixmapCacheEvent);
}
qint64 PixmapCacheModel::lastTimeMark() const
{
return d->eventList.last().startTime;
}
void PixmapCacheModel::setExpanded(int category, bool expanded)
{
Q_UNUSED(category);
d->isExpanded = expanded;
}
int PixmapCacheModel::categoryDepth(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
if (isEmpty())
return 1;
if (d->isExpanded)
return d->expandedRowCount;
return d->collapsedRowCount;
}
int PixmapCacheModel::categoryCount() const
{
return 1;
}
const QString PixmapCacheModel::categoryLabel(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
return QLatin1String("Pixmap Cache");
}
int PixmapCacheModel::findFirstIndex(qint64 startTime) const
{
int candidate = findFirstIndexNoParents(startTime);
return candidate;
}
int PixmapCacheModel::findFirstIndexNoParents(qint64 startTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.count() == 1 || d->eventList.first().startTime+d->eventList.first().duration >= startTime)
return 0;
else
if (d->eventList.last().startTime+d->eventList.last().duration <= startTime)
return -1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime + d->eventList[midIndex].duration < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return toIndex;
}
int PixmapCacheModel::findLastIndex(qint64 endTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.first().startTime >= endTime)
return -1;
if (d->eventList.count() == 1)
return 0;
if (d->eventList.last().startTime <= endTime)
return d->eventList.count()-1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime < endTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return fromIndex;
}
int PixmapCacheModel::getEventType(int index) const
{
Q_UNUSED(index);
return QmlDebug::PixmapCacheEvent;
}
int PixmapCacheModel::getEventCategory(int index) const
{
Q_UNUSED(index);
return 0;
}
int PixmapCacheModel::getEventRow(int index) const
{
if (d->isExpanded)
return d->eventList[index].rowNumberExpanded;
return d->eventList[index].rowNumberCollapsed;
}
qint64 PixmapCacheModel::getDuration(int index) const
{
return d->eventList[index].duration;
}
qint64 PixmapCacheModel::getStartTime(int index) const
{
return d->eventList[index].startTime;
}
qint64 PixmapCacheModel::getEndTime(int index) const
{
return getStartTime(index)+getDuration(index);
}
int PixmapCacheModel::getEventId(int index) const
{
return d->eventList[index].eventId;
}
QColor PixmapCacheModel::getColor(int index) const
{
if (d->eventList[index].pixmapEventType == PixmapCacheCountChanged)
return QColor::fromHsl(240, 76, 166);
int ndx = getEventId(index);
return QColor::fromHsl((ndx*25)%360, 76, 166);
}
float PixmapCacheModel::getHeight(int index) const
{
if (d->eventList[index].pixmapEventType == PixmapCacheCountChanged) {
float scale = d->maxCacheSize - d->minCacheSize;
float fraction = 1.0f;
if (scale > 1)
fraction = (float)(d->eventList[index].cacheSize -
d->minCacheSize) / scale;
return fraction * 0.85f + 0.15f;
}
return 1.0f;
}
QString getFilenameOnly(QString absUrl)
{
int characterPos = absUrl.lastIndexOf(QLatin1Char('/'))+1;
if (characterPos < absUrl.length())
absUrl = absUrl.mid(characterPos);
return absUrl;
}
const QVariantList PixmapCacheModel::getLabelsForCategory(int category) const
{
Q_UNUSED(category);
QVariantList result;
if (d->isExpanded && !isEmpty()) {
{
// Cache Size
QVariantMap element;
element.insert(QLatin1String("displayName"), QVariant(QLatin1String("Cache Size")));
element.insert(QLatin1String("description"), QVariant(QLatin1String("Cache Size")));
element.insert(QLatin1String("id"), QVariant(0));
result << element;
}
for (int i=0; i < d->pixmapUrls.count(); i++) {
// Loading
QVariantMap element;
element.insert(QLatin1String("displayName"), QVariant(getFilenameOnly(d->pixmapUrls[i])));
element.insert(QLatin1String("description"), QVariant(getFilenameOnly(d->pixmapUrls[i])));
element.insert(QLatin1String("id"), QVariant(i+1));
result << element;
}
}
return result;
}
QString PixmapCacheModel::PixmapCacheModelPrivate::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
void PixmapCacheModel::PixmapCacheModelPrivate::addVP(QVariantList &l, QString label, qint64 time)
{
if (time > 0) {
QVariantMap res;
res.insert(label, QVariant(displayTime(time)));
l << res;
}
}
const QVariantList PixmapCacheModel::getEventDetails(int index) const
{
QVariantList result;
PixmapCacheEvent *ev = &d->eventList[index];
{
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;
res.insert(tr("File"), QVariant(getFilenameOnly(d->pixmapUrls[ev->urlIndex])));
result << res;
}
{
QVariantMap res;
res.insert(tr("Width"), QVariant(QString::fromLatin1("%1 px").arg(d->pixmapSizes[ev->urlIndex].first)));
result << res;
res.clear();
res.insert(tr("Height"), QVariant(QString::fromLatin1("%1 px").arg(d->pixmapSizes[ev->urlIndex].second)));
result << res;
}
if (ev->pixmapEventType == PixmapLoadingStarted && ev->cacheSize == -1) {
QVariantMap res;
res.insert(tr("Result"), QVariant(QLatin1String("Load Error")));
result << res;
}
return result;
}
const QVariantMap PixmapCacheModel::getEventLocation(int /*index*/) const
{
QVariantMap map;
return map;
}
bool compareStartTimes(const PixmapCacheModel::PixmapCacheEvent&t1, const PixmapCacheModel::PixmapCacheEvent &t2)
{
return t1.startTime < t2.startTime;
}
void PixmapCacheModel::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
int lastCacheSizeEvent = -1;
int cumulatedCount = 0;
QVector < int > pixmapStartPoints;
foreach (const QmlProfilerSimpleModel::QmlEventData &event, simpleModel->getEvents()) {
if (!eventAccepted(event))
continue;
PixmapCacheEvent newEvent;
newEvent.pixmapEventType = event.bindingType;
newEvent.startTime = event.startTime;
newEvent.duration = 0;
bool isNewEntry = false;
newEvent.urlIndex = d->pixmapUrls.indexOf(event.location.filename);
if (newEvent.urlIndex == -1) {
isNewEntry = true;
newEvent.urlIndex = d->pixmapUrls.count();
d->pixmapUrls << event.location.filename;
d->pixmapSizes << QPair<int, int>(0,0); // default value
pixmapStartPoints << d->eventList.count(); // index to the starting point
}
if (newEvent.pixmapEventType == PixmapSizeKnown) { // pixmap size
d->pixmapSizes[newEvent.urlIndex] = QPair<int,int>((int)event.numericData1, (int)event.numericData2);
}
newEvent.eventId = newEvent.urlIndex + 1;
// Cache Size Changed Event
if (newEvent.pixmapEventType == PixmapCacheCountChanged) {
newEvent.startTime = event.startTime + 1; // delay 1 ns for proper sorting
newEvent.eventId = 0;
newEvent.rowNumberExpanded = 1;
newEvent.rowNumberCollapsed = 1;
qint64 pixSize = d->pixmapSizes[newEvent.urlIndex].first * d->pixmapSizes[newEvent.urlIndex].second;
qint64 prevSize = 0;
if (lastCacheSizeEvent != -1) {
prevSize = d->eventList[lastCacheSizeEvent].cacheSize;
if (event.numericData3 < cumulatedCount)
pixSize = -pixSize;
cumulatedCount = event.numericData3;
d->eventList[lastCacheSizeEvent].duration = newEvent.startTime - d->eventList[lastCacheSizeEvent].startTime;
}
newEvent.cacheSize = prevSize + pixSize;
d->eventList << newEvent;
lastCacheSizeEvent = d->eventList.count() - 1;
}
// Load
if (newEvent.pixmapEventType == PixmapLoadingStarted) {
pixmapStartPoints[newEvent.urlIndex] = d->eventList.count();
newEvent.rowNumberExpanded = newEvent.urlIndex + 2;
d->eventList << newEvent;
}
if (newEvent.pixmapEventType == PixmapLoadingFinished || newEvent.pixmapEventType == PixmapLoadingError) {
int loadIndex = pixmapStartPoints[newEvent.urlIndex];
if (!isNewEntry) {
d->eventList[loadIndex].duration = event.startTime - d->eventList[loadIndex].startTime;
} else {
// if it's a new entry it means that we don't have a corresponding start
newEvent.pixmapEventType = PixmapLoadingStarted;
newEvent.rowNumberExpanded = newEvent.urlIndex + 2;
newEvent.startTime = traceStartTime();
newEvent.duration = event.startTime - traceStartTime();
d->eventList << newEvent;
}
if (event.bindingType == PixmapLoadingFinished)
d->eventList[loadIndex].cacheSize = 1; // use count to mark success
else
d->eventList[loadIndex].cacheSize = -1; // ... or failure
}
}
if (lastCacheSizeEvent != -1) {
d->eventList[lastCacheSizeEvent].duration = traceEndTime() - d->eventList[lastCacheSizeEvent].startTime;
}
d->resizeUnfinishedLoads();
qSort(d->eventList.begin(), d->eventList.end(), compareStartTimes);
d->computeCacheSizes();
d->flattenLoads();
d->computeRowCounts();
}
void PixmapCacheModel::clear()
{
d->eventList.clear();
d->pixmapUrls.clear();
d->pixmapSizes.clear();
d->collapsedRowCount = 1;
d->expandedRowCount = 1;
}
void PixmapCacheModel::dataChanged()
{
if (m_modelManager->state() == QmlProfilerDataState::Done)
loadData();
if (m_modelManager->state() == QmlProfilerDataState::Empty)
clear();
emit stateChanged();
emit dataAvailable();
emit emptyChanged();
return;
}
void PixmapCacheModel::PixmapCacheModelPrivate::computeCacheSizes()
{
minCacheSize = -1;
maxCacheSize = -1;
foreach (const PixmapCacheModel::PixmapCacheEvent &event, eventList) {
if (event.pixmapEventType == PixmapCacheModel::PixmapCacheCountChanged) {
if (minCacheSize == -1 || event.cacheSize < minCacheSize)
minCacheSize = event.cacheSize;
if (maxCacheSize == -1 || event.cacheSize > maxCacheSize)
maxCacheSize = event.cacheSize;
}
}
}
void PixmapCacheModel::PixmapCacheModelPrivate::resizeUnfinishedLoads()
{
// all the "load start" events with duration 0 continue till the end of the trace
for (int i = 0; i < eventList.count(); i++) {
if (eventList[i].pixmapEventType == PixmapCacheModel::PixmapLoadingStarted &&
eventList[i].duration == 0) {
eventList[i].duration = q->traceEndTime() - eventList[i].startTime;
}
}
}
void PixmapCacheModel::PixmapCacheModelPrivate::flattenLoads()
{
// computes "compressed row"
QVector <qint64> eventEndTimes;
for (int i = 0; i < eventList.count(); i++) {
PixmapCacheModel::PixmapCacheEvent *event = &eventList[i];
if (event->pixmapEventType == PixmapCacheModel::PixmapLoadingStarted) {
event->rowNumberCollapsed = 0;
while (eventEndTimes.count() > event->rowNumberCollapsed &&
eventEndTimes[event->rowNumberCollapsed] > event->startTime)
event->rowNumberCollapsed++;
if (eventEndTimes.count() == event->rowNumberCollapsed)
eventEndTimes << 0; // increase stack length, proper value added below
eventEndTimes[event->rowNumberCollapsed] = event->startTime + event->duration;
// readjust to account for category empty row and bargraph
event->rowNumberCollapsed += 2;
}
}
}
void PixmapCacheModel::PixmapCacheModelPrivate::computeRowCounts()
{
expandedRowCount = 0;
collapsedRowCount = 0;
foreach (const PixmapCacheModel::PixmapCacheEvent &event, eventList) {
if (event.rowNumberExpanded > expandedRowCount)
expandedRowCount = event.rowNumberExpanded;
if (event.rowNumberCollapsed > collapsedRowCount)
collapsedRowCount = event.rowNumberCollapsed;
}
// Starting from 0, count is maxIndex+1
expandedRowCount++;
collapsedRowCount++;
}
} // namespace Internal
} // namespace QmlProfilerExtension

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#ifndef PIXMAPCACHEMODEL_H
#define PIXMAPCACHEMODEL_H
#include "qmlprofiler/abstracttimelinemodel.h"
#include "qmlprofiler/qmlprofilermodelmanager.h"
#include "qmlprofiler/qmlprofilersimplemodel.h"
#include <QStringList>
#include <QColor>
namespace QmlProfilerExtension {
namespace Internal {
class PixmapCacheModel : public QmlProfiler::AbstractTimelineModel
{
Q_OBJECT
public:
struct PixmapCacheEvent {
int eventId;
qint64 startTime;
qint64 duration;
int pixmapEventType;
int urlIndex;
qint64 cacheSize;
int rowNumberExpanded;
int rowNumberCollapsed;
};
enum PixmapEventType {
PixmapSizeKnown,
PixmapReferenceCountChanged,
PixmapCacheCountChanged,
PixmapLoadingStarted,
PixmapLoadingFinished,
PixmapLoadingError,
MaximumPixmapEventType
};
PixmapCacheModel(QObject *parent = 0);
~PixmapCacheModel();
// void setModelManager(QmlProfiler::Internal::QmlProfilerModelManager *modelManager);
int categories() const;
QStringList categoryTitles() const;
QString name() const;
int count() const;
bool isEmpty() const;
bool eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE void setExpanded(int category, bool expanded);
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
Q_INVOKABLE int categoryCount() const;
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
int findFirstIndex(qint64 startTime) const;
int findFirstIndexNoParents(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
int getEventType(int index) const;
int getEventCategory(int index) const;
int getEventRow(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE int getEventId(int index) const;
Q_INVOKABLE QColor getColor(int index) const;
Q_INVOKABLE float getHeight(int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
void loadData();
void clear();
//signals:
// void countChanged();
// void dataAvailable();
// void stateChanged();
// void emptyChanged();
// void expandedChanged();
protected slots:
void dataChanged();
private:
class PixmapCacheModelPrivate;
PixmapCacheModelPrivate *d;
};
} // namespace Internal
} // namespace QmlProfilerExtension
#endif // PIXMAPCACHEMODEL_H

View File

@@ -0,0 +1,23 @@
TARGET = QmlProfilerExtension
TEMPLATE = lib
PROVIDER = Digia
include(../../qtcreatorplugin.pri)
include(qmlprofilerextension_dependencies.pri)
DEFINES += QMLPROFILEREXTENSION_LIBRARY
# QmlProfilerExtension files
SOURCES += qmlprofilerextensionplugin.cpp \
scenegraphtimelinemodel.cpp \
pixmapcachemodel.cpp
HEADERS += qmlprofilerextensionplugin.h \
qmlprofilerextension_global.h \
qmlprofilerextensionconstants.h \
scenegraphtimelinemodel.h \
pixmapcachemodel.h
OTHER_FILES += \
QmlProfilerExtension.json

View File

@@ -0,0 +1,6 @@
QTC_PLUGIN_NAME = QmlProfilerExtension
#QTC_LIB_DEPENDS += \
# qmldebug \
# extensionsystem
QTC_PLUGIN_DEPENDS += \
qmlprofiler

View File

@@ -0,0 +1,31 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#ifndef QMLPROFILEREXTENSION_GLOBAL_H
#define QMLPROFILEREXTENSION_GLOBAL_H
#include <QtGlobal>
#if defined(QMLPROFILEREXTENSION_LIBRARY)
# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_EXPORT
#else
# define QMLPROFILEREXTENSIONSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // QMLPROFILEREXTENSION_GLOBAL_H

View File

@@ -0,0 +1,32 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#ifndef QMLPROFILEREXTENSIONCONSTANTS_H
#define QMLPROFILEREXTENSIONCONSTANTS_H
namespace QmlProfilerExtension {
namespace Constants {
const char ACTION_ID[] = "QmlProfilerExtension.Action";
const char MENU_ID[] = "QmlProfilerExtension.Menu";
} // namespace QmlProfilerExtension
} // namespace Constants
#endif // QMLPROFILEREXTENSIONCONSTANTS_H

View File

@@ -0,0 +1,93 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#include "qmlprofilerextensionplugin.h"
#include "qmlprofilerextensionconstants.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/coreconstants.h>
#include <QAction>
#include <QMessageBox>
#include <QMainWindow>
#include <QMenu>
#include <QtPlugin>
#include "scenegraphtimelinemodel.h"
#include "pixmapcachemodel.h"
using namespace QmlProfilerExtension::Internal;
QmlProfilerExtensionPlugin::QmlProfilerExtensionPlugin()
{
// Create your members
}
QmlProfilerExtensionPlugin::~QmlProfilerExtensionPlugin()
{
// Unregister objects from the plugin manager's object pool
// Delete members
}
bool QmlProfilerExtensionPlugin::initialize(const QStringList &arguments, QString *errorString)
{
// Register objects in the plugin manager's object pool
// Load settings
// Add actions to menus
// Connect to other plugins' signals
// In the initialize method, a plugin can be sure that the plugins it
// depends on have initialized their members.
Q_UNUSED(arguments)
Q_UNUSED(errorString)
addAutoReleasedObject(new PixmapCacheModel);
addAutoReleasedObject(new SceneGraphTimelineModel);
return true;
}
void QmlProfilerExtensionPlugin::extensionsInitialized()
{
// Retrieve objects from the plugin manager's object pool
// In the extensionsInitialized method, a plugin can be sure that all
// plugins that depend on it are completely initialized.
}
ExtensionSystem::IPlugin::ShutdownFlag QmlProfilerExtensionPlugin::aboutToShutdown()
{
// Save settings
// Disconnect from signals that are not needed during shutdown
// Hide UI (if you add UI that is not in the main window directly)
return SynchronousShutdown;
}
void QmlProfilerExtensionPlugin::triggerAction()
{
QMessageBox::information(Core::ICore::mainWindow(),
tr("Action triggered"),
tr("This is an action from QmlProfilerExtension."));
}
Q_EXPORT_PLUGIN2(QmlProfilerExtension, QmlProfilerExtensionPlugin)

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#ifndef QMLPROFILEREXTENSION_H
#define QMLPROFILEREXTENSION_H
#include "qmlprofilerextension_global.h"
#include <extensionsystem/iplugin.h>
namespace QmlProfilerExtension {
namespace Internal {
class QmlProfilerExtensionPlugin : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QmlProfilerExtension.json")
public:
QmlProfilerExtensionPlugin();
~QmlProfilerExtensionPlugin();
bool initialize(const QStringList &arguments, QString *errorString);
void extensionsInitialized();
ShutdownFlag aboutToShutdown();
private slots:
void triggerAction();
};
} // namespace Internal
} // namespace QmlProfilerExtension
#endif // QMLPROFILEREXTENSION_H

View File

@@ -0,0 +1,475 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#include "scenegraphtimelinemodel.h"
#include "qmldebug/qmlprofilereventtypes.h"
#include "qmlprofiler/qmlprofilermodelmanager.h"
#include <QCoreApplication>
#include <QDebug>
namespace QmlProfilerExtension {
namespace Internal {
using namespace QmlProfiler::Internal;
enum SceneGraphEventType {
SceneGraphRendererFrame,
SceneGraphAdaptationLayerFrame,
SceneGraphContextFrame,
SceneGraphRenderLoopFrame,
SceneGraphTexturePrepare,
SceneGraphTextureDeletion,
SceneGraphPolishAndSync,
SceneGraphWindowsRenderShow,
SceneGraphWindowsAnimations,
SceneGraphWindowsPolishFrame,
MaximumSceneGraphFrameType
};
enum SceneGraphCategoryType {
SceneGraphRenderThread,
SceneGraphGUIThread,
MaximumSceneGraphCategoryType
};
class SceneGraphTimelineModel::SceneGraphTimelineModelPrivate {
public:
SceneGraphTimelineModelPrivate(SceneGraphTimelineModel *qq):q(qq) {}
~SceneGraphTimelineModelPrivate();
SceneGraphTimelineModel *q;
QVector < SceneGraphTimelineModel::SceneGraphEvent > eventList;
bool isExpanded;
QString displayTime(double time);
void addVP(QVariantList &l, QString label, qint64 time);
};
SceneGraphTimelineModel::SceneGraphTimelineModel(QObject *parent)
: AbstractTimelineModel(parent), d(new SceneGraphTimelineModelPrivate(this))
{
}
SceneGraphTimelineModel::~SceneGraphTimelineModel()
{
}
int SceneGraphTimelineModel::categories() const
{
return 1;
}
QStringList SceneGraphTimelineModel::categoryTitles() const
{
QStringList retString;
retString << categoryLabel(0);
return retString;
}
QString SceneGraphTimelineModel::name() const
{
return QLatin1String("SceneGraphTimeLineModel");
}
int SceneGraphTimelineModel::count() const
{
return d->eventList.count();
}
bool SceneGraphTimelineModel::isEmpty() const
{
return d->eventList.isEmpty();
}
bool SceneGraphTimelineModel::eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const
{
return (event.eventType == QmlDebug::SceneGraphFrameEvent);
}
qint64 SceneGraphTimelineModel::lastTimeMark() const
{
return d->eventList.last().startTime;
}
void SceneGraphTimelineModel::setExpanded(int category, bool expanded)
{
Q_UNUSED(category);
d->isExpanded = expanded;
}
int SceneGraphTimelineModel::categoryDepth(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
if (isEmpty())
return 1;
return 3;
}
int SceneGraphTimelineModel::categoryCount() const
{
return 1;
}
const QString SceneGraphTimelineModel::categoryLabel(int categoryIndex) const
{
Q_UNUSED(categoryIndex);
return tr("Scene Graph");
}
int SceneGraphTimelineModel::findFirstIndex(qint64 startTime) const
{
int candidate = findFirstIndexNoParents(startTime);
// because there's two threads synchronized, the right index could be one off
if (candidate > 0 && d->eventList[candidate-1].startTime + d->eventList[candidate-1].duration >= startTime)
return candidate - 1;
return candidate;
}
int SceneGraphTimelineModel::findFirstIndexNoParents(qint64 startTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.count() == 1 || d->eventList.first().startTime+d->eventList.first().duration >= startTime)
return 0;
else
if (d->eventList.last().startTime+d->eventList.last().duration <= startTime)
return -1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime + d->eventList[midIndex].duration < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return toIndex;
}
int SceneGraphTimelineModel::findLastIndex(qint64 endTime) const
{
if (d->eventList.isEmpty())
return -1;
if (d->eventList.first().startTime >= endTime)
return -1;
if (d->eventList.count() == 1)
return 0;
if (d->eventList.last().startTime <= endTime)
return d->eventList.count()-1;
int fromIndex = 0;
int toIndex = d->eventList.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->eventList[midIndex].startTime < endTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return fromIndex;
}
int SceneGraphTimelineModel::getEventType(int index) const
{
Q_UNUSED(index);
return QmlDebug::SceneGraphFrameEvent;
}
int SceneGraphTimelineModel::getEventCategory(int index) const
{
Q_UNUSED(index);
return 0;
}
int SceneGraphTimelineModel::getEventRow(int index) const
{
return d->eventList[index].sgEventType + 1;
if (d->isExpanded)
return d->eventList[index].sgEventType + 1;
else
return 0;
}
qint64 SceneGraphTimelineModel::getDuration(int index) const
{
return d->eventList[index].duration;
}
qint64 SceneGraphTimelineModel::getStartTime(int index) const
{
return d->eventList[index].startTime;
}
qint64 SceneGraphTimelineModel::getEndTime(int index) const
{
return getStartTime(index)+getDuration(index);
}
int SceneGraphTimelineModel::getEventId(int index) const
{
return d->eventList[index].sgEventType;
}
QColor SceneGraphTimelineModel::getColor(int index) const
{
// get duration in seconds
double eventDuration = getDuration(index) / 1e9;
// supposedly never above 60 frames per second
// limit it in that case
if (eventDuration < 1/60.0)
eventDuration = 1/60.0;
// generate hue based on fraction of the 60fps
double fpsFraction = 1 / (eventDuration * 60.0);
if (fpsFraction > 1.0)
fpsFraction = 1.0;
return QColor::fromHsl((fpsFraction*96)+10, 76, 166);
}
float SceneGraphTimelineModel::getHeight(int index) const
{
Q_UNUSED(index);
return 1.0f;
}
QString labelForSGType(int t)
{
switch ((SceneGraphCategoryType)t) {
case SceneGraphRenderThread:
return QCoreApplication::translate("SceneGraphTimelineModel", "Renderer Thread");
case SceneGraphGUIThread:
return QCoreApplication::translate("SceneGraphTimelineModel", "GUI Thread");
default: return QString();
}
}
const QVariantList SceneGraphTimelineModel::getLabelsForCategory(int category) const
{
Q_UNUSED(category);
QVariantList result;
if (d->isExpanded && !isEmpty()) {
for (int i = 0; i < MaximumSceneGraphCategoryType; i++) {
QVariantMap element;
element.insert(QLatin1String("displayName"), QVariant(labelForSGType(i)));
element.insert(QLatin1String("description"), QVariant(labelForSGType(i)));
element.insert(QLatin1String("id"), QVariant(i));
result << element;
}
}
return result;
}
QString SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::displayTime(double time)
{
if (time < 1e6)
return QString::number(time/1e3,'f',3) + trUtf8(" \xc2\xb5s");
if (time < 1e9)
return QString::number(time/1e6,'f',3) + tr(" ms");
return QString::number(time/1e9,'f',3) + tr(" s");
}
void SceneGraphTimelineModel::SceneGraphTimelineModelPrivate::addVP(QVariantList &l, QString label, qint64 time)
{
if (time > 0) {
QVariantMap res;
res.insert(label, QVariant(displayTime(time)));
l << res;
}
}
const QVariantList SceneGraphTimelineModel::getEventDetails(int index) const
{
QVariantList result;
SceneGraphEvent *ev = &d->eventList[index];
{
QVariantMap res;
res.insert(QLatin1String("title"), QVariant(labelForSGType(ev->sgEventType)));
result << res;
}
d->addVP(result, tr("Duration"), ev->duration );
if (ev->sgEventType == SceneGraphRenderThread) {
d->addVP(result, tr("Polish"), ev->timing[14]);
d->addVP(result, tr("Sync"), ev->timing[0]);
d->addVP(result, tr("Preprocess"), ev->timing[1]);
d->addVP(result, tr("Upload"), ev->timing[2]);
d->addVP(result, tr("Swizzle"), ev->timing[3]);
d->addVP(result, tr("Convert"), ev->timing[4]);
d->addVP(result, tr("Mipmap"), ev->timing[5]);
d->addVP(result, tr("Bind"), ev->timing[6]);
d->addVP(result, tr("Material"), ev->timing[7]);
d->addVP(result, tr("Glyph Render"), ev->timing[8]);
d->addVP(result, tr("Glyph Store"), ev->timing[9]);
d->addVP(result, tr("Update"), ev->timing[10]);
d->addVP(result, tr("Binding"), ev->timing[11]);
d->addVP(result, tr("Render"), ev->timing[12]);
d->addVP(result, tr("Swap"), ev->timing[13]);
d->addVP(result, tr("Animations"), ev->timing[15]);
}
if (ev->sgEventType == SceneGraphGUIThread) {
d->addVP(result, tr("Polish"), ev->timing[0]);
d->addVP(result, tr("Wait"), ev->timing[1]);
d->addVP(result, tr("Sync"), ev->timing[2]);
d->addVP(result, tr("Animations"), ev->timing[3]);
}
return result;
}
const QVariantMap SceneGraphTimelineModel::getEventLocation(int /*index*/) const
{
QVariantMap map;
return map;
}
bool compareStartTimes(const SceneGraphTimelineModel::SceneGraphEvent&t1, const SceneGraphTimelineModel::SceneGraphEvent &t2)
{
return t1.startTime < t2.startTime;
}
void SceneGraphTimelineModel::loadData()
{
clear();
QmlProfilerSimpleModel *simpleModel = m_modelManager->simpleModel();
if (simpleModel->isEmpty())
return;
int lastRenderEvent = -1;
// combine the data of several eventtypes into two rows
foreach (const QmlProfilerSimpleModel::QmlEventData &event, simpleModel->getEvents()) {
if (!eventAccepted(event))
continue;
if (event.bindingType == SceneGraphRenderLoopFrame) {
SceneGraphEvent newEvent;
newEvent.sgEventType = SceneGraphRenderThread;
newEvent.duration = event.numericData1 + event.numericData2 + event.numericData3;
newEvent.startTime = event.startTime - newEvent.duration;
for (int i=0; i < timingFieldCount; i++)
newEvent.timing[i] = 0;
d->eventList << newEvent;
lastRenderEvent = d->eventList.count()-1;
}
if (lastRenderEvent >= 0) {
switch ((SceneGraphEventType)event.bindingType) {
case SceneGraphRendererFrame: {
d->eventList[lastRenderEvent].timing[1] = event.numericData1;
d->eventList[lastRenderEvent].timing[10] = event.numericData2;
d->eventList[lastRenderEvent].timing[11] = event.numericData3;
d->eventList[lastRenderEvent].timing[12] = event.numericData4;
break;
}
case SceneGraphAdaptationLayerFrame: {
d->eventList[lastRenderEvent].timing[8] = event.numericData2;
d->eventList[lastRenderEvent].timing[9] = event.numericData3;
break;
}
case SceneGraphContextFrame: {
d->eventList[lastRenderEvent].timing[7] = event.numericData1;
break;
}
case SceneGraphRenderLoopFrame: {
d->eventList[lastRenderEvent].timing[0] = event.numericData1;
d->eventList[lastRenderEvent].timing[13] = event.numericData3;
break;
}
case SceneGraphTexturePrepare: {
d->eventList[lastRenderEvent].timing[2] = event.numericData4;
d->eventList[lastRenderEvent].timing[3] = event.numericData3;
d->eventList[lastRenderEvent].timing[4] = event.numericData2;
d->eventList[lastRenderEvent].timing[5] = event.numericData5;
d->eventList[lastRenderEvent].timing[6] = event.numericData1;
break;
}
case SceneGraphPolishAndSync: {
// GUI thread
SceneGraphEvent newEvent;
newEvent.sgEventType = SceneGraphGUIThread;
newEvent.duration = event.numericData1 + event.numericData2 + event.numericData3 + event.numericData4;
newEvent.startTime = event.startTime - newEvent.duration;
for (int i=0; i < timingFieldCount; i++)
newEvent.timing[i] = 0;
newEvent.timing[0] = event.numericData1;
newEvent.timing[1] = event.numericData2;
newEvent.timing[2] = event.numericData3;
newEvent.timing[3] = event.numericData4;
d->eventList << newEvent;
break;
}
case SceneGraphWindowsAnimations: {
d->eventList[lastRenderEvent].timing[14] = event.numericData1;
break;
}
case SceneGraphWindowsPolishFrame: {
d->eventList[lastRenderEvent].timing[15] = event.numericData1;
break;
}
default: break;
}
}
}
qSort(d->eventList.begin(), d->eventList.end(), compareStartTimes);
}
void SceneGraphTimelineModel::clear()
{
d->eventList.clear();
}
void SceneGraphTimelineModel::dataChanged()
{
if (m_modelManager->state() == QmlProfilerDataState::Done)
loadData();
if (m_modelManager->state() == QmlProfilerDataState::Empty)
clear();
emit stateChanged();
emit dataAvailable();
emit emptyChanged();
return;
}
} // namespace Internal
} // namespace QmlProfilerExtension

View File

@@ -0,0 +1,109 @@
/****************************************************************************
**
** 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/>
**
** This file is part of the Qt Enterprise Qt Quick Profiler Add-on.
**
** Licensees holding valid Qt Enterprise licenses may use this file in
** accordance with the Qt Enterprise License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** 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/>
**
****************************************************************************/
#ifndef SCENEGRAPHTIMELINEMODEL_H
#define SCENEGRAPHTIMELINEMODEL_H
#include "qmlprofiler/abstracttimelinemodel.h"
#include "qmlprofiler/qmlprofilermodelmanager.h"
#include "qmlprofiler/qmlprofilersimplemodel.h"
#include <QStringList>
#include <QColor>
namespace QmlProfilerExtension {
namespace Internal {
#define timingFieldCount 16
class SceneGraphTimelineModel : public QmlProfiler::AbstractTimelineModel
{
Q_OBJECT
public:
struct SceneGraphEvent {
qint64 startTime;
qint64 duration;
int sgEventType;
qint64 timing[timingFieldCount];
};
SceneGraphTimelineModel(QObject *parent = 0);
~SceneGraphTimelineModel();
// void setModelManager(QmlProfiler::Internal::QmlProfilerModelManager *modelManager);
int categories() const;
QStringList categoryTitles() const;
QString name() const;
int count() const;
bool isEmpty() const;
bool eventAccepted(const QmlProfiler::Internal::QmlProfilerSimpleModel::QmlEventData &event) const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE void setExpanded(int category, bool expanded);
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
Q_INVOKABLE int categoryCount() const;
Q_INVOKABLE const QString categoryLabel(int categoryIndex) const;
int findFirstIndex(qint64 startTime) const;
int findFirstIndexNoParents(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
int getEventType(int index) const;
int getEventCategory(int index) const;
int getEventRow(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE int getEventId(int index) const;
Q_INVOKABLE QColor getColor(int index) const;
Q_INVOKABLE float getHeight(int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
void loadData();
void clear();
//signals:
// void countChanged();
// void dataAvailable();
// void stateChanged();
// void emptyChanged();
// void expandedChanged();
protected slots:
void dataChanged();
private:
class SceneGraphTimelineModelPrivate;
SceneGraphTimelineModelPrivate *d;
};
} // namespace Internal
} // namespace QmlProfilerExtension
#endif // SCENEGRAPHTIMELINEMODEL_H