qmlprofilerrangemodel.cpp 9.66 KB
Newer Older
Christiaan Janssen's avatar
Christiaan Janssen committed
1 2
/****************************************************************************
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
Christiaan Janssen's avatar
Christiaan Janssen committed
4 5 6 7 8 9 10 11 12
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
Eike Ziller's avatar
Eike Ziller committed
13 14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
Christiaan Janssen's avatar
Christiaan Janssen committed
15 16 17
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
Christiaan Janssen's avatar
Christiaan Janssen committed
24 25 26 27 28 29 30
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

31
#include "qmlprofilerrangemodel.h"
Christiaan Janssen's avatar
Christiaan Janssen committed
32
#include "qmlprofilermodelmanager.h"
33
#include "qmlprofilerdatamodel.h"
34 35 36 37
#include "qmlprofilerbindingloopsrenderpass.h"
#include "timelinenotesrenderpass.h"
#include "timelineitemsrenderpass.h"
#include "timelineselectionrenderpass.h"
Christiaan Janssen's avatar
Christiaan Janssen committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51

#include <QCoreApplication>
#include <QVector>
#include <QHash>
#include <QUrl>
#include <QString>
#include <QStack>

#include <QDebug>

namespace QmlProfiler {
namespace Internal {


52
QmlProfilerRangeModel::QmlProfilerRangeModel(QmlProfilerModelManager *manager,
53 54
                                             QmlDebug::RangeType range, QObject *parent) :
    QmlProfilerTimelineModel(manager, categoryLabel(range), QmlDebug::MaximumMessage, range, parent)
Christiaan Janssen's avatar
Christiaan Janssen committed
55
{
56
    m_expandedRowTypes << -1;
57
    announceFeatures(1ULL << QmlDebug::featureFromRangeType(rangeType()));
58 59
}

60
void QmlProfilerRangeModel::clear()
Christiaan Janssen's avatar
Christiaan Janssen committed
61
{
62 63 64
    m_expandedRowTypes.clear();
    m_expandedRowTypes << -1;
    m_data.clear();
65
    QmlProfilerTimelineModel::clear();
Christiaan Janssen's avatar
Christiaan Janssen committed
66 67
}

68 69 70 71 72
bool QmlProfilerRangeModel::supportsBindingLoops() const
{
    return rangeType() == QmlDebug::Binding || rangeType() == QmlDebug::HandlingSignal;
}

73
void QmlProfilerRangeModel::loadData()
Christiaan Janssen's avatar
Christiaan Janssen committed
74 75
{
    clear();
76
    QmlProfilerDataModel *simpleModel = modelManager()->qmlModel();
Christiaan Janssen's avatar
Christiaan Janssen committed
77 78 79 80
    if (simpleModel->isEmpty())
        return;

    // collect events
81 82
    const QVector<QmlProfilerDataModel::QmlEventData> &eventList = simpleModel->getEvents();
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
83
    foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
84
        const QmlProfilerDataModel::QmlEventTypeData &type = typesList[event.typeIndex];
85
        if (!accepted(type))
Christiaan Janssen's avatar
Christiaan Janssen committed
86 87 88
            continue;

        // store starttime-based instance
89 90 91
        m_data.insert(insert(event.startTime, event.duration, event.typeIndex),
                      QmlRangeEventStartInstance());
        updateProgress(count(), eventList.count() * 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
92 93
    }

94
    updateProgress(2, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
95

96
    // compute range nesting
97
    computeNesting();
Christiaan Janssen's avatar
Christiaan Janssen committed
98 99

    // compute nestingLevel - nonexpanded
100
    computeNestingContracted();
Christiaan Janssen's avatar
Christiaan Janssen committed
101

102
    updateProgress(3, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
103 104

    // compute nestingLevel - expanded
105
    computeExpandedLevels();
Christiaan Janssen's avatar
Christiaan Janssen committed
106

107
    updateProgress(4, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
108

109 110
    if (supportsBindingLoops())
        findBindingLoops();
Christiaan Janssen's avatar
Christiaan Janssen committed
111

112
    updateProgress(5, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
113

114
    updateProgress(1, 1);
Christiaan Janssen's avatar
Christiaan Janssen committed
115 116
}

117
void QmlProfilerRangeModel::computeNestingContracted()
Christiaan Janssen's avatar
Christiaan Janssen committed
118 119
{
    int i;
120
    int eventCount = count();
Christiaan Janssen's avatar
Christiaan Janssen committed
121

122
    int nestingLevels = QmlDebug::Constants::QML_MIN_LEVEL;
123
    int collapsedRowCount = nestingLevels + 1;
124 125
    QVector<qint64> nestingEndTimes;
    nestingEndTimes.fill(0, nestingLevels + 1);
Christiaan Janssen's avatar
Christiaan Janssen committed
126 127

    for (i = 0; i < eventCount; i++) {
128
        qint64 st = startTime(i);
Christiaan Janssen's avatar
Christiaan Janssen committed
129 130

        // per type
131
        if (nestingEndTimes[nestingLevels] > st) {
132
            if (++nestingLevels == nestingEndTimes.size())
133
                nestingEndTimes << 0;
134 135
            if (nestingLevels == collapsedRowCount)
                ++collapsedRowCount;
Christiaan Janssen's avatar
Christiaan Janssen committed
136
        } else {
137 138 139
            while (nestingLevels > QmlDebug::Constants::QML_MIN_LEVEL &&
                   nestingEndTimes[nestingLevels-1] <= st)
                nestingLevels--;
Christiaan Janssen's avatar
Christiaan Janssen committed
140
        }
141
        nestingEndTimes[nestingLevels] = st + duration(i);
Christiaan Janssen's avatar
Christiaan Janssen committed
142

143
        m_data[i].displayRowCollapsed = nestingLevels;
Christiaan Janssen's avatar
Christiaan Janssen committed
144
    }
145
    setCollapsedRowCount(collapsedRowCount);
Christiaan Janssen's avatar
Christiaan Janssen committed
146 147
}

148
void QmlProfilerRangeModel::computeExpandedLevels()
Christiaan Janssen's avatar
Christiaan Janssen committed
149 150
{
    QHash<int, int> eventRow;
151
    int eventCount = count();
Christiaan Janssen's avatar
Christiaan Janssen committed
152
    for (int i = 0; i < eventCount; i++) {
153 154 155 156
        int eventTypeId = typeId(i);
        if (!eventRow.contains(eventTypeId)) {
            eventRow[eventTypeId] = m_expandedRowTypes.size();
            m_expandedRowTypes << eventTypeId;
Christiaan Janssen's avatar
Christiaan Janssen committed
157
        }
158
        m_data[i].displayRowExpanded = eventRow[eventTypeId];
Christiaan Janssen's avatar
Christiaan Janssen committed
159
    }
160
    setExpandedRowCount(m_expandedRowTypes.size());
Christiaan Janssen's avatar
Christiaan Janssen committed
161 162
}

163
void QmlProfilerRangeModel::findBindingLoops()
Christiaan Janssen's avatar
Christiaan Janssen committed
164
{
165
    typedef QPair<int, int> CallStackEntry;
Christiaan Janssen's avatar
Christiaan Janssen committed
166 167
    QStack<CallStackEntry> callStack;

168 169
    for (int i = 0; i < count(); ++i) {
        int potentialParent = callStack.isEmpty() ? -1 : callStack.top().second;
Christiaan Janssen's avatar
Christiaan Janssen committed
170

171
        while (potentialParent != -1 && !(endTime(potentialParent) > startTime(i))) {
Christiaan Janssen's avatar
Christiaan Janssen committed
172
            callStack.pop();
173
            potentialParent = callStack.isEmpty() ? -1 : callStack.top().second;
Christiaan Janssen's avatar
Christiaan Janssen committed
174 175 176 177
        }

        // check whether event is already in stack
        for (int ii = 0; ii < callStack.size(); ++ii) {
178 179
            if (callStack.at(ii).first == typeId(i)) {
                m_data[i].bindingLoopHead = callStack.at(ii).second;
Christiaan Janssen's avatar
Christiaan Janssen committed
180 181 182 183
                break;
            }
        }

184
        CallStackEntry newEntry(typeId(i), i);
Christiaan Janssen's avatar
Christiaan Janssen committed
185 186 187 188 189 190 191
        callStack.push(newEntry);
    }

}

/////////////////// QML interface

192
QString QmlProfilerRangeModel::categoryLabel(QmlDebug::RangeType rangeType)
Christiaan Janssen's avatar
Christiaan Janssen committed
193
{
194 195
    return QCoreApplication::translate("MainView",
            QmlProfilerModelManager::featureName(QmlDebug::featureFromRangeType(rangeType)));
Christiaan Janssen's avatar
Christiaan Janssen committed
196 197
}

198
int QmlProfilerRangeModel::expandedRow(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
199
{
200 201 202 203 204 205
    return m_data[index].displayRowExpanded;
}

int QmlProfilerRangeModel::collapsedRow(int index) const
{
    return m_data[index].displayRowCollapsed;
Christiaan Janssen's avatar
Christiaan Janssen committed
206 207
}

208
int QmlProfilerRangeModel::bindingLoopDest(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
209
{
210
    return m_data[index].bindingLoopHead;
Christiaan Janssen's avatar
Christiaan Janssen committed
211 212
}

213
QColor QmlProfilerRangeModel::color(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
214
{
215
    return colorBySelectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
216 217
}

218
QVariantList QmlProfilerRangeModel::labels() const
Christiaan Janssen's avatar
Christiaan Janssen committed
219 220 221
{
    QVariantList result;

222 223 224 225 226 227 228 229 230
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
            modelManager()->qmlModel()->getEventTypes();
    for (int i = 1; i < expandedRowCount(); i++) { // Ignore the -1 for the first row
        QVariantMap element;
        int typeId = m_expandedRowTypes[i];
        element.insert(QLatin1String("displayName"), QVariant(types[typeId].displayName));
        element.insert(QLatin1String("description"), QVariant(types[typeId].data));
        element.insert(QLatin1String("id"), QVariant(typeId));
        result << element;
Christiaan Janssen's avatar
Christiaan Janssen committed
231 232 233 234 235
    }

    return result;
}

236
QVariantMap QmlProfilerRangeModel::details(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
237
{
238
    QVariantMap result;
239
    int id = selectionId(index);
240
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
241
            modelManager()->qmlModel()->getEventTypes();
Christiaan Janssen's avatar
Christiaan Janssen committed
242

243
    result.insert(QStringLiteral("displayName"), categoryLabel(rangeType()));
244
    result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(duration(index)));
Christiaan Janssen's avatar
Christiaan Janssen committed
245

246
    result.insert(tr("Details"), types[id].data);
247
    result.insert(tr("Location"), types[id].displayName);
Christiaan Janssen's avatar
Christiaan Janssen committed
248 249 250
    return result;
}

251
QVariantMap QmlProfilerRangeModel::location(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
252 253
{
    QVariantMap result;
254
    int id = selectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
255

256
    const QmlDebug::QmlEventLocation &location
257
            = modelManager()->qmlModel()->getEventTypes().at(id).location;
Christiaan Janssen's avatar
Christiaan Janssen committed
258

259 260 261
    result.insert(QStringLiteral("file"), location.filename);
    result.insert(QStringLiteral("line"), location.line);
    result.insert(QStringLiteral("column"), location.column);
Christiaan Janssen's avatar
Christiaan Janssen committed
262 263 264 265

    return result;
}

266
int QmlProfilerRangeModel::typeId(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
267
{
268
    return selectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
269 270
}

271
int QmlProfilerRangeModel::selectionIdForLocation(const QString &filename, int line, int column) const
Christiaan Janssen's avatar
Christiaan Janssen committed
272 273
{
    // if this is called from v8 view, we don't have the column number, it will be -1
274
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
275 276 277
            modelManager()->qmlModel()->getEventTypes();
    for (int i = 1; i < expandedRowCount(); ++i) {
        int typeId = m_expandedRowTypes[i];
278
        const QmlProfilerDataModel::QmlEventTypeData &eventData = types[typeId];
Christiaan Janssen's avatar
Christiaan Janssen committed
279 280 281
        if (eventData.location.filename == filename &&
                eventData.location.line == line &&
                (column == -1 || eventData.location.column == column))
282
            return typeId;
Christiaan Janssen's avatar
Christiaan Janssen committed
283 284 285 286
    }
    return -1;
}

287
QList<const Timeline::TimelineRenderPass *> QmlProfilerRangeModel::supportedRenderPasses() const
288 289
{
    if (supportsBindingLoops()) {
290 291
        QList<const Timeline::TimelineRenderPass *> passes;
        passes << Timeline::TimelineItemsRenderPass::instance()
292
               << QmlProfilerBindingLoopsRenderPass::instance()
293 294
               << Timeline::TimelineSelectionRenderPass::instance()
               << Timeline::TimelineNotesRenderPass::instance();
295 296 297 298
        return passes;
    } else {
        return QmlProfilerTimelineModel::supportedRenderPasses();
    }
Christiaan Janssen's avatar
Christiaan Janssen committed
299

300
}
Christiaan Janssen's avatar
Christiaan Janssen committed
301 302 303

}
}