Commit 35cedb2a authored by Ulf Hermann's avatar Ulf Hermann

QmlProfiler: Allow string data in events

The restriction to put all strings in the type data is becoming a
burden to further enhancements. Also, introduce proper ctors for all
event structs.

Change-Id: I42d3bac96155ac1ac183a2b82785ce0396c5a932
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@theqtcompany.com>
parent 8d936b8a
......@@ -81,20 +81,21 @@ void QmlProfilerAnimationsModel::loadData()
qint64 minNextStartTimes[] = {0, 0};
foreach (const QmlProfilerDataModel::QmlEventData &event, referenceList) {
const QmlProfilerDataModel::QmlEventTypeData &type = typeList[event.typeIndex];
const QmlProfilerDataModel::QmlEventTypeData &type = typeList[event.typeIndex()];
if (!accepted(type))
continue;
lastThread = (QmlDebug::AnimationThread)event.numericData3;
lastThread = (QmlDebug::AnimationThread)event.numericData(2);
// initial estimation of the event duration: 1/framerate
qint64 estimatedDuration = event.numericData1 > 0 ? 1e9/event.numericData1 : 1;
qint64 estimatedDuration = event.numericData(0) > 0 ? 1e9/event.numericData(0) : 1;
// the profiler registers the animation events at the end of them
qint64 realEndTime = event.startTime;
qint64 realEndTime = event.startTime();
// ranges should not overlap. If they do, our estimate wasn't accurate enough
qint64 realStartTime = qMax(event.startTime - estimatedDuration, minNextStartTimes[lastThread]);
qint64 realStartTime = qMax(event.startTime() - estimatedDuration,
minNextStartTimes[lastThread]);
// Sometimes our estimate is far off or the server has miscalculated the frame rate
if (realStartTime >= realEndTime)
......@@ -102,9 +103,9 @@ void QmlProfilerAnimationsModel::loadData()
// Don't "fix" the framerate even if we've fixed the duration.
// The server should know better after all and if it doesn't we want to see that.
lastEvent.typeId = event.typeIndex;
lastEvent.framerate = (int)event.numericData1;
lastEvent.animationcount = (int)event.numericData2;
lastEvent.typeId = event.typeIndex();
lastEvent.framerate = (int)event.numericData(0);
lastEvent.animationcount = (int)event.numericData(1);
QTC_ASSERT(lastEvent.animationcount > 0, continue);
m_data.insert(insert(realStartTime, realEndTime - realStartTime, lastThread), lastEvent);
......@@ -112,9 +113,10 @@ void QmlProfilerAnimationsModel::loadData()
if (lastThread == QmlDebug::GuiThread)
m_maxGuiThreadAnimations = qMax(lastEvent.animationcount, m_maxGuiThreadAnimations);
else
m_maxRenderThreadAnimations = qMax(lastEvent.animationcount, m_maxRenderThreadAnimations);
m_maxRenderThreadAnimations = qMax(lastEvent.animationcount,
m_maxRenderThreadAnimations);
minNextStartTimes[lastThread] = event.startTime + 1;
minNextStartTimes[lastThread] = event.startTime() + 1;
updateProgress(count(), referenceList.count());
}
......
......@@ -194,7 +194,7 @@ bool QmlProfilerDataModel::isEmpty() const
inline static bool operator<(const QmlProfilerDataModel::QmlEventData &t1,
const QmlProfilerDataModel::QmlEventData &t2)
{
return t1.startTime < t2.startTime;
return t1.startTime() < t2.startTime();
}
inline static uint qHash(const QmlProfilerDataModel::QmlEventTypeData &type)
......@@ -266,15 +266,15 @@ void QmlProfilerDataModel::addQmlEvent(QmlDebug::Message message, QmlDebug::Rang
Q_D(QmlProfilerDataModel);
QString displayName;
QmlEventTypeData typeData = {displayName, location, message, rangeType, detailType, data};
QmlEventData eventData = {-1, startTime, duration, ndata1, ndata2, ndata3, ndata4, ndata5};
QmlEventTypeData typeData(displayName, location, message, rangeType, detailType, data);
QmlEventData eventData(startTime, duration, -1, ndata1, ndata2, ndata3, ndata4, ndata5);
QHash<QmlEventTypeData, int>::Iterator it = d->eventTypeIds.find(typeData);
if (it != d->eventTypeIds.end()) {
eventData.typeIndex = it.value();
eventData.setTypeIndex(it.value());
} else {
eventData.typeIndex = d->eventTypes.size();
d->eventTypeIds[typeData] = eventData.typeIndex;
eventData.setTypeIndex(d->eventTypes.size());
d->eventTypeIds[typeData] = eventData.typeIndex();
d->eventTypes.append(typeData);
}
......@@ -290,7 +290,7 @@ qint64 QmlProfilerDataModel::lastTimeMark() const
if (d->eventList.isEmpty())
return 0;
return d->eventList.last().startTime + d->eventList.last().duration;
return d->eventList.last().startTime() + d->eventList.last().duration();
}
void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString)
......
......@@ -43,6 +43,15 @@ class QMLPROFILER_EXPORT QmlProfilerDataModel : public QObject
Q_OBJECT
public:
struct QmlEventTypeData {
QmlEventTypeData(const QString &displayName = QString(),
const QmlDebug::QmlEventLocation &location = QmlDebug::QmlEventLocation(),
QmlDebug::Message message = QmlDebug::MaximumMessage,
QmlDebug::RangeType rangeType = QmlDebug::MaximumRangeType,
int detailType = -1, const QString &data = QString()) :
displayName(displayName), location(location), message(message), rangeType(rangeType),
detailType(detailType), data(data)
{}
QString displayName;
QmlDebug::QmlEventLocation location;
QmlDebug::Message message;
......@@ -52,17 +61,143 @@ public:
};
struct QmlEventData {
int typeIndex;
qint64 startTime;
qint64 duration;
qint64 numericData1;
qint64 numericData2;
qint64 numericData3;
qint64 numericData4;
qint64 numericData5;
QmlEventData(qint64 startTime = -1, qint64 duration = -1, int typeIndex = -1,
qint64 num0 = 0, qint64 num1 = 0, qint64 num2 = 0, qint64 num3 = 0,
qint64 num4 = 0) :
m_startTime(startTime), m_duration(duration), m_dataType(NumericData),
m_typeIndex(typeIndex)
{
m_numericData[0] = num0;
m_numericData[1] = num1;
m_numericData[2] = num2;
m_numericData[3] = num3;
m_numericData[4] = num4;
}
QmlEventData(qint64 startTime, qint64 duration, int typeIndex, const QString &data)
: m_startTime(startTime), m_duration(duration), m_typeIndex(typeIndex)
{
assignStringData(data);
}
QmlEventData(const QmlEventData &other) :
m_startTime(other.m_startTime), m_duration(other.m_duration),
m_dataType(other.m_dataType), m_typeIndex(other.m_typeIndex)
{
assignData(other);
}
QmlEventData &operator=(const QmlEventData &other)
{
if (this != &other) {
if (m_dataType == StringData)
m_stringData.~QString();
m_startTime = other.m_startTime;
m_duration = other.m_duration;
m_typeIndex = other.m_typeIndex;
m_dataType = other.m_dataType;
assignData(other);
}
return *this;
}
~QmlEventData()
{
if (m_dataType == StringData)
m_stringData.~QString();
}
qint64 startTime() const { return m_startTime; }
void setStartTime(qint64 startTime) { m_startTime = startTime; }
qint64 duration() const { return m_duration; }
void setDuration(qint64 duration) { m_duration = duration; }
int typeIndex() const { return m_typeIndex; }
void setTypeIndex(int typeIndex) { m_typeIndex = typeIndex; }
qint64 numericData(int i) const { return m_dataType == NumericData ? m_numericData[i] : 0; }
void setNumericData(int i, qint64 data)
{
if (m_dataType == StringData)
m_stringData.~QString();
m_dataType = NumericData;
m_numericData[i] = data;
}
QString stringData() const
{
switch (m_dataType) {
case NumericData: return QString();
case StringData: return m_stringData;
default: return QString::fromUtf8(m_characterData, m_characterDataLength);
}
}
void setStringData(const QString &data)
{
if (m_dataType == StringData)
m_stringData.~QString();
assignStringData(data);
}
private:
static const quint8 StringData = 254;
static const quint8 NumericData = 255;
qint64 m_startTime;
qint64 m_duration;
union {
qint64 m_numericData[5];
QString m_stringData;
char m_characterData[5 * sizeof(qint64) + 3];
};
union {
quint8 m_dataType;
quint8 m_characterDataLength;
};
qint32 m_typeIndex;
void assignData(const QmlEventData &other)
{
switch (m_dataType) {
case StringData:
new (&m_stringData) QString(other.m_stringData);
break;
case NumericData:
for (int i = 0; i < 5; ++i)
m_numericData[i] = other.m_numericData[i];
break;
default:
memcpy(m_characterData, other.m_characterData, m_characterDataLength);
break;
}
}
void assignStringData(const QString &data)
{
QByteArray cdata = data.toUtf8();
if (cdata.length() <= (int)sizeof(m_characterData)) {
m_characterDataLength = cdata.length();
memcpy(m_characterData, cdata.constData(), m_characterDataLength);
} else {
m_dataType = StringData;
new (&m_stringData) QString(data);
}
}
};
struct QmlEventNoteData {
QmlEventNoteData(int typeIndex = -1, qint64 startTime = -1, qint64 duration = -1,
const QString &text = QString()) :
typeIndex(typeIndex), startTime(startTime), duration(duration), text(text)
{}
int typeIndex;
qint64 startTime;
qint64 duration;
......
......@@ -196,34 +196,34 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
for (int i = 0; i < eventList.size(); ++i) {
const QmlProfilerDataModel::QmlEventData *event = &eventList[i];
const QmlProfilerDataModel::QmlEventTypeData *type = &typesList[event->typeIndex];
const QmlProfilerDataModel::QmlEventTypeData *type = &typesList[event->typeIndex()];
if (!d->acceptedTypes.contains(type->rangeType))
continue;
if (checkRanges) {
if ((event->startTime + event->duration < rangeStart)
|| (event->startTime > rangeEnd))
if ((event->startTime() + event->duration() < rangeStart)
|| (event->startTime() > rangeEnd))
continue;
}
// update stats
QmlEventStats *stats = &d->data[event->typeIndex];
QmlEventStats *stats = &d->data[event->typeIndex()];
stats->duration += event->duration;
if (event->duration < stats->minTime)
stats->minTime = event->duration;
if (event->duration > stats->maxTime)
stats->maxTime = event->duration;
stats->duration += event->duration();
if (event->duration() < stats->minTime)
stats->minTime = event->duration();
if (event->duration() > stats->maxTime)
stats->maxTime = event->duration();
stats->calls++;
// for median computing
durations[event->typeIndex].append(event->duration);
durations[event->typeIndex()].append(event->duration());
// qml time computation
if (event->startTime > lastEndTime) { // assume parent event if starts before last end
qmlTime += event->duration;
lastEndTime = event->startTime + event->duration;
if (event->startTime() > lastEndTime) { // assume parent event if starts before last end
qmlTime += event->duration();
lastEndTime = event->startTime() + event->duration();
}
......@@ -231,16 +231,16 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
// binding loop detection
//
const QmlProfilerDataModel::QmlEventData *potentialParent = callStack.top();
while (potentialParent
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
while (potentialParent && !(potentialParent->startTime() + potentialParent->duration() >
event->startTime())) {
callStack.pop();
potentialParent = callStack.top();
}
// check whether event is already in stack
for (int ii = 1; ii < callStack.size(); ++ii) {
if (callStack.at(ii)->typeIndex == event->typeIndex) {
d->eventsInBindingLoop.insert(event->typeIndex);
if (callStack.at(ii)->typeIndex() == event->typeIndex()) {
d->eventsInBindingLoop.insert(event->typeIndex());
break;
}
}
......@@ -374,30 +374,31 @@ void QmlProfilerEventParentsModelProxy::loadData()
const QVector<QmlProfilerDataModel::QmlEventTypeData> typesList = simpleModel->getEventTypes();
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
// whitelist
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex].rangeType))
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex()].rangeType))
continue;
// level computation
if (endtimesPerLevel[level] > event.startTime) {
if (endtimesPerLevel[level] > event.startTime()) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
while (level > QmlDebug::Constants::QML_MIN_LEVEL &&
endtimesPerLevel[level-1] <= event.startTime())
level--;
}
endtimesPerLevel[level] = event.startTime + event.duration;
endtimesPerLevel[level] = event.startTime() + event.duration();
int parentTypeIndex = -1;
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
parentTypeIndex = lastParent[level-1];
QmlEventRelativesMap &relativesMap = m_data[event.typeIndex];
QmlEventRelativesMap &relativesMap = m_data[event.typeIndex()];
QmlEventRelativesMap::Iterator it = relativesMap.find(parentTypeIndex);
if (it != relativesMap.end()) {
it.value().calls++;
it.value().duration += event.duration;
it.value().duration += event.duration();
} else {
QmlEventRelativesData parent = {
event.duration,
event.duration(),
1,
eventsInBindingLoop.contains(parentTypeIndex)
};
......@@ -405,7 +406,7 @@ void QmlProfilerEventParentsModelProxy::loadData()
}
// now lastparent is the new type
lastParent[level] = event.typeIndex;
lastParent[level] = event.typeIndex();
}
}
......@@ -438,17 +439,18 @@ void QmlProfilerEventChildrenModelProxy::loadData()
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
// whitelist
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex].rangeType))
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex()].rangeType))
continue;
// level computation
if (endtimesPerLevel[level] > event.startTime) {
if (endtimesPerLevel[level] > event.startTime()) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= event.startTime)
while (level > QmlDebug::Constants::QML_MIN_LEVEL &&
endtimesPerLevel[level-1] <= event.startTime())
level--;
}
endtimesPerLevel[level] = event.startTime + event.duration;
endtimesPerLevel[level] = event.startTime() + event.duration();
int parentId = -1;
......@@ -456,21 +458,21 @@ void QmlProfilerEventChildrenModelProxy::loadData()
parentId = lastParent[level-1];
QmlEventRelativesMap &relativesMap = m_data[parentId];
QmlEventRelativesMap::Iterator it = relativesMap.find(event.typeIndex);
QmlEventRelativesMap::Iterator it = relativesMap.find(event.typeIndex());
if (it != relativesMap.end()) {
it.value().calls++;
it.value().duration += event.duration;
it.value().duration += event.duration();
} else {
QmlEventRelativesData child = {
event.duration,
event.duration(),
1,
eventsInBindingLoop.contains(parentId)
};
relativesMap.insert(event.typeIndex, child);
relativesMap.insert(event.typeIndex(), child);
}
// now lastparent is the new type
lastParent[level] = event.typeIndex;
lastParent[level] = event.typeIndex();
}
}
......
......@@ -80,12 +80,12 @@ void QmlProfilerRangeModel::loadData()
const QVector<QmlProfilerDataModel::QmlEventData> &eventList = simpleModel->getEvents();
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
const QmlProfilerDataModel::QmlEventTypeData &type = typesList[event.typeIndex];
const QmlProfilerDataModel::QmlEventTypeData &type = typesList[event.typeIndex()];
if (!accepted(type))
continue;
// store starttime-based instance
m_data.insert(insert(event.startTime, event.duration, event.typeIndex),
m_data.insert(insert(event.startTime(), event.duration(), event.typeIndex()),
QmlRangeEventStartInstance());
updateProgress(count(), eventList.count() * 5);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment