qmlprofilerrangemodel.cpp 8.84 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"
Christiaan Janssen's avatar
Christiaan Janssen committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47

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

#include <QDebug>

namespace QmlProfiler {
namespace Internal {


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

56
void QmlProfilerRangeModel::clear()
Christiaan Janssen's avatar
Christiaan Janssen committed
57
{
58
59
60
    m_expandedRowTypes.clear();
    m_expandedRowTypes << -1;
    m_data.clear();
61
    QmlProfilerTimelineModel::clear();
Christiaan Janssen's avatar
Christiaan Janssen committed
62
63
}

64
void QmlProfilerRangeModel::loadData()
Christiaan Janssen's avatar
Christiaan Janssen committed
65
66
{
    clear();
67
    QmlProfilerDataModel *simpleModel = modelManager()->qmlModel();
Christiaan Janssen's avatar
Christiaan Janssen committed
68
69
70
71
    if (simpleModel->isEmpty())
        return;

    // collect events
72
73
    const QVector<QmlProfilerDataModel::QmlEventData> &eventList = simpleModel->getEvents();
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
74
    foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
75
        const QmlProfilerDataModel::QmlEventTypeData &type = typesList[event.typeIndex];
76
        if (!accepted(type))
Christiaan Janssen's avatar
Christiaan Janssen committed
77
78
79
            continue;

        // store starttime-based instance
80
81
82
        m_data.insert(insert(event.startTime, event.duration, event.typeIndex),
                      QmlRangeEventStartInstance());
        updateProgress(count(), eventList.count() * 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
83
84
    }

85
    updateProgress(2, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
86

87
    // compute range nesting
88
    computeNesting();
Christiaan Janssen's avatar
Christiaan Janssen committed
89
90

    // compute nestingLevel - nonexpanded
91
    computeNestingContracted();
Christiaan Janssen's avatar
Christiaan Janssen committed
92

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

    // compute nestingLevel - expanded
96
    computeExpandedLevels();
Christiaan Janssen's avatar
Christiaan Janssen committed
97

98
    updateProgress(4, 6);
Christiaan Janssen's avatar
Christiaan Janssen committed
99

100
    findBindingLoops();
Christiaan Janssen's avatar
Christiaan Janssen committed
101

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

104
    updateProgress(1, 1);
Christiaan Janssen's avatar
Christiaan Janssen committed
105
106
}

107
void QmlProfilerRangeModel::computeNestingContracted()
Christiaan Janssen's avatar
Christiaan Janssen committed
108
109
{
    int i;
110
    int eventCount = count();
Christiaan Janssen's avatar
Christiaan Janssen committed
111

112
    int nestingLevels = QmlDebug::Constants::QML_MIN_LEVEL;
113
    int collapsedRowCount = nestingLevels + 1;
114
115
    QVector<qint64> nestingEndTimes;
    nestingEndTimes.fill(0, nestingLevels + 1);
Christiaan Janssen's avatar
Christiaan Janssen committed
116
117

    for (i = 0; i < eventCount; i++) {
118
        qint64 st = startTime(i);
Christiaan Janssen's avatar
Christiaan Janssen committed
119
120

        // per type
121
        if (nestingEndTimes[nestingLevels] > st) {
122
            if (++nestingLevels == nestingEndTimes.size())
123
                nestingEndTimes << 0;
124
125
            if (nestingLevels == collapsedRowCount)
                ++collapsedRowCount;
Christiaan Janssen's avatar
Christiaan Janssen committed
126
        } else {
127
128
129
            while (nestingLevels > QmlDebug::Constants::QML_MIN_LEVEL &&
                   nestingEndTimes[nestingLevels-1] <= st)
                nestingLevels--;
Christiaan Janssen's avatar
Christiaan Janssen committed
130
        }
131
        nestingEndTimes[nestingLevels] = st + duration(i);
Christiaan Janssen's avatar
Christiaan Janssen committed
132

133
        m_data[i].displayRowCollapsed = nestingLevels;
Christiaan Janssen's avatar
Christiaan Janssen committed
134
    }
135
    setCollapsedRowCount(collapsedRowCount);
Christiaan Janssen's avatar
Christiaan Janssen committed
136
137
}

138
void QmlProfilerRangeModel::computeExpandedLevels()
Christiaan Janssen's avatar
Christiaan Janssen committed
139
140
{
    QHash<int, int> eventRow;
141
    int eventCount = count();
Christiaan Janssen's avatar
Christiaan Janssen committed
142
    for (int i = 0; i < eventCount; i++) {
143
144
145
146
        int eventTypeId = typeId(i);
        if (!eventRow.contains(eventTypeId)) {
            eventRow[eventTypeId] = m_expandedRowTypes.size();
            m_expandedRowTypes << eventTypeId;
Christiaan Janssen's avatar
Christiaan Janssen committed
147
        }
148
        m_data[i].displayRowExpanded = eventRow[eventTypeId];
Christiaan Janssen's avatar
Christiaan Janssen committed
149
    }
150
    setExpandedRowCount(m_expandedRowTypes.size());
Christiaan Janssen's avatar
Christiaan Janssen committed
151
152
}

153
void QmlProfilerRangeModel::findBindingLoops()
Christiaan Janssen's avatar
Christiaan Janssen committed
154
{
155
    if (rangeType() != QmlDebug::Binding && rangeType() != QmlDebug::HandlingSignal)
156
157
        return;

158
    typedef QPair<int, int> CallStackEntry;
Christiaan Janssen's avatar
Christiaan Janssen committed
159
160
    QStack<CallStackEntry> callStack;

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

164
        while (potentialParent != -1 && !(endTime(potentialParent) > startTime(i))) {
Christiaan Janssen's avatar
Christiaan Janssen committed
165
            callStack.pop();
166
            potentialParent = callStack.isEmpty() ? -1 : callStack.top().second;
Christiaan Janssen's avatar
Christiaan Janssen committed
167
168
169
170
        }

        // check whether event is already in stack
        for (int ii = 0; ii < callStack.size(); ++ii) {
171
172
            if (callStack.at(ii).first == typeId(i)) {
                m_data[i].bindingLoopHead = callStack.at(ii).second;
Christiaan Janssen's avatar
Christiaan Janssen committed
173
174
175
176
                break;
            }
        }

177
        CallStackEntry newEntry(typeId(i), i);
Christiaan Janssen's avatar
Christiaan Janssen committed
178
179
180
181
182
183
184
        callStack.push(newEntry);
    }

}

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

185
QString QmlProfilerRangeModel::categoryLabel(QmlDebug::RangeType rangeType)
Christiaan Janssen's avatar
Christiaan Janssen committed
186
{
187
188
    return QCoreApplication::translate("MainView",
            QmlProfilerModelManager::featureName(QmlDebug::featureFromRangeType(rangeType)));
Christiaan Janssen's avatar
Christiaan Janssen committed
189
190
}

191
int QmlProfilerRangeModel::row(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
192
{
193
194
    if (expanded())
        return m_data[index].displayRowExpanded;
Christiaan Janssen's avatar
Christiaan Janssen committed
195
    else
196
        return m_data[index].displayRowCollapsed;
Christiaan Janssen's avatar
Christiaan Janssen committed
197
198
}

199
int QmlProfilerRangeModel::bindingLoopDest(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
200
{
201
    return m_data[index].bindingLoopHead;
Christiaan Janssen's avatar
Christiaan Janssen committed
202
203
}

204
QColor QmlProfilerRangeModel::color(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
205
{
206
    return colorBySelectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
207
208
}

209
QVariantList QmlProfilerRangeModel::labels() const
Christiaan Janssen's avatar
Christiaan Janssen committed
210
211
212
{
    QVariantList result;

213
214
215
216
217
218
219
220
221
    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
222
223
224
225
226
    }

    return result;
}

227
QVariantMap QmlProfilerRangeModel::details(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
228
{
229
    QVariantMap result;
230
    int id = selectionId(index);
231
    const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
232
            modelManager()->qmlModel()->getEventTypes();
Christiaan Janssen's avatar
Christiaan Janssen committed
233

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

237
    result.insert(tr("Details"), types[id].data);
238
    result.insert(tr("Location"), types[id].displayName);
Christiaan Janssen's avatar
Christiaan Janssen committed
239
240
241
    return result;
}

242
QVariantMap QmlProfilerRangeModel::location(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
243
244
{
    QVariantMap result;
245
    int id = selectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
246

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

250
251
252
    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
253
254
255
256

    return result;
}

257
int QmlProfilerRangeModel::typeId(int index) const
Christiaan Janssen's avatar
Christiaan Janssen committed
258
{
259
    return selectionId(index);
Christiaan Janssen's avatar
Christiaan Janssen committed
260
261
}

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



}
}