forked from qt-creator/qt-creator
QmlProfiler: showing children time and count in events pane
Change-Id: Ia285d1c84312e6a314fbf1c59c62b571b4c3e7d4 Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
@@ -54,10 +54,115 @@ const char *const TYPE_COMPILING_STR = "Compiling";
|
|||||||
const char *const TYPE_CREATING_STR = "Creating";
|
const char *const TYPE_CREATING_STR = "Creating";
|
||||||
const char *const TYPE_BINDING_STR = "Binding";
|
const char *const TYPE_BINDING_STR = "Binding";
|
||||||
const char *const TYPE_HANDLINGSIGNAL_STR = "HandlingSignal";
|
const char *const TYPE_HANDLINGSIGNAL_STR = "HandlingSignal";
|
||||||
|
const char *const PROFILER_FILE_VERSION = "1.01";
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MIN_LEVEL 1
|
#define MIN_LEVEL 1
|
||||||
|
|
||||||
|
QmlEventData::QmlEventData()
|
||||||
|
{
|
||||||
|
line = -1;
|
||||||
|
eventType = MaximumQmlEventType;
|
||||||
|
eventId = -1;
|
||||||
|
duration = 0;
|
||||||
|
calls = 0;
|
||||||
|
minTime = 0;
|
||||||
|
maxTime = 0;
|
||||||
|
timePerCall = 0;
|
||||||
|
percentOfTime = 0;
|
||||||
|
medianTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlEventData::~QmlEventData()
|
||||||
|
{
|
||||||
|
qDeleteAll(parentHash.values());
|
||||||
|
parentHash.clear();
|
||||||
|
qDeleteAll(childrenHash.values());
|
||||||
|
childrenHash.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlEventData &QmlEventData::operator=(const QmlEventData &ref)
|
||||||
|
{
|
||||||
|
if (this == &ref)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
displayname = ref.displayname;
|
||||||
|
filename = ref.filename;
|
||||||
|
eventHashStr = ref.eventHashStr;
|
||||||
|
details = ref.details;
|
||||||
|
line = ref.line;
|
||||||
|
eventType = ref.eventType;
|
||||||
|
duration = ref.duration;
|
||||||
|
calls = ref.calls;
|
||||||
|
minTime = ref.minTime;
|
||||||
|
maxTime = ref.maxTime;
|
||||||
|
timePerCall = ref.timePerCall;
|
||||||
|
percentOfTime = ref.percentOfTime;
|
||||||
|
medianTime = ref.medianTime;
|
||||||
|
eventId = ref.eventId;
|
||||||
|
|
||||||
|
qDeleteAll(parentHash.values());
|
||||||
|
parentHash.clear();
|
||||||
|
foreach (const QString &key, ref.parentHash.keys()) {
|
||||||
|
parentHash.insert(key, new QmlEventSub(ref.parentHash.value(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
qDeleteAll(childrenHash.values());
|
||||||
|
childrenHash.clear();
|
||||||
|
foreach (const QString &key, ref.childrenHash.keys()) {
|
||||||
|
childrenHash.insert(key, new QmlEventSub(ref.childrenHash.value(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QV8EventData::QV8EventData()
|
||||||
|
{
|
||||||
|
line = -1;
|
||||||
|
eventId = -1;
|
||||||
|
totalTime = 0;
|
||||||
|
selfTime = 0;
|
||||||
|
totalPercent = 0;
|
||||||
|
selfPercent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QV8EventData::~QV8EventData()
|
||||||
|
{
|
||||||
|
qDeleteAll(parentHash.values());
|
||||||
|
parentHash.clear();
|
||||||
|
qDeleteAll(childrenHash.values());
|
||||||
|
childrenHash.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QV8EventData &QV8EventData::operator=(const QV8EventData &ref)
|
||||||
|
{
|
||||||
|
if (this == &ref)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
displayName = ref.displayName;
|
||||||
|
filename = ref.filename;
|
||||||
|
functionName = ref.functionName;
|
||||||
|
line = ref.line;
|
||||||
|
totalTime = ref.totalTime;
|
||||||
|
totalPercent = ref.totalPercent;
|
||||||
|
selfTime = ref.selfTime;
|
||||||
|
selfPercent = ref.selfPercent;
|
||||||
|
eventId = ref.eventId;
|
||||||
|
|
||||||
|
qDeleteAll(parentHash.values());
|
||||||
|
parentHash.clear();
|
||||||
|
foreach (const QString &key, ref.parentHash.keys()) {
|
||||||
|
parentHash.insert(key, new QV8EventSub(ref.parentHash.value(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
qDeleteAll(childrenHash.values());
|
||||||
|
childrenHash.clear();
|
||||||
|
foreach (const QString &key, ref.childrenHash.keys()) {
|
||||||
|
childrenHash.insert(key, new QV8EventSub(ref.childrenHash.value(key)));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// endtimedata
|
// endtimedata
|
||||||
struct QmlEventEndTimeData {
|
struct QmlEventEndTimeData {
|
||||||
qint64 endTime;
|
qint64 endTime;
|
||||||
@@ -151,6 +256,10 @@ public:
|
|||||||
|
|
||||||
QmlProfilerEventList *q;
|
QmlProfilerEventList *q;
|
||||||
|
|
||||||
|
// convenience functions
|
||||||
|
void clearQmlRootEvent();
|
||||||
|
void clearV8RootEvent();
|
||||||
|
|
||||||
// Stored data
|
// Stored data
|
||||||
QmlEventHash m_eventDescriptions;
|
QmlEventHash m_eventDescriptions;
|
||||||
QList<QmlEventEndTimeData> m_endTimeSortedList;
|
QList<QmlEventEndTimeData> m_endTimeSortedList;
|
||||||
@@ -160,6 +269,11 @@ public:
|
|||||||
QV8EventDescriptions m_v8EventList;
|
QV8EventDescriptions m_v8EventList;
|
||||||
QHash<int, QV8EventData *> m_v8parents;
|
QHash<int, QV8EventData *> m_v8parents;
|
||||||
|
|
||||||
|
QmlEventData m_qmlRootEvent;
|
||||||
|
QV8EventData m_v8RootEvent;
|
||||||
|
QString m_rootEventName;
|
||||||
|
QString m_rootEventDesc;
|
||||||
|
|
||||||
QHash<int, QmlEventTypeCount *> m_typeCounts;
|
QHash<int, QmlEventTypeCount *> m_typeCounts;
|
||||||
|
|
||||||
qint64 m_traceEndTime;
|
qint64 m_traceEndTime;
|
||||||
@@ -184,6 +298,11 @@ QmlProfilerEventList::QmlProfilerEventList(QObject *parent) :
|
|||||||
d->m_traceStartTime = -1;
|
d->m_traceStartTime = -1;
|
||||||
d->m_qmlMeasuredTime = 0;
|
d->m_qmlMeasuredTime = 0;
|
||||||
d->m_v8MeasuredTime = 0;
|
d->m_v8MeasuredTime = 0;
|
||||||
|
d->m_rootEventName = tr("<program>");
|
||||||
|
d->m_rootEventDesc = tr("Main Program");
|
||||||
|
d->clearQmlRootEvent();
|
||||||
|
d->clearV8RootEvent();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerEventList::~QmlProfilerEventList()
|
QmlProfilerEventList::~QmlProfilerEventList()
|
||||||
@@ -193,17 +312,20 @@ QmlProfilerEventList::~QmlProfilerEventList()
|
|||||||
|
|
||||||
void QmlProfilerEventList::clear()
|
void QmlProfilerEventList::clear()
|
||||||
{
|
{
|
||||||
foreach (QmlEventData *binding, d->m_eventDescriptions.values())
|
qDeleteAll(d->m_eventDescriptions.values());
|
||||||
delete binding;
|
|
||||||
d->m_eventDescriptions.clear();
|
d->m_eventDescriptions.clear();
|
||||||
|
|
||||||
|
qDeleteAll(d->m_v8EventList);
|
||||||
|
d->m_v8EventList.clear();
|
||||||
|
|
||||||
d->m_endTimeSortedList.clear();
|
d->m_endTimeSortedList.clear();
|
||||||
d->m_startTimeSortedList.clear();
|
d->m_startTimeSortedList.clear();
|
||||||
|
|
||||||
qDeleteAll(d->m_v8EventList);
|
|
||||||
d->m_v8EventList.clear();
|
|
||||||
d->m_v8parents.clear();
|
d->m_v8parents.clear();
|
||||||
|
|
||||||
|
d->clearQmlRootEvent();
|
||||||
|
d->clearV8RootEvent();
|
||||||
|
|
||||||
foreach (QmlEventTypeCount *typeCount, d->m_typeCounts.values())
|
foreach (QmlEventTypeCount *typeCount, d->m_typeCounts.values())
|
||||||
delete typeCount;
|
delete typeCount;
|
||||||
d->m_typeCounts.clear();
|
d->m_typeCounts.clear();
|
||||||
@@ -249,24 +371,10 @@ void QmlProfilerEventList::addRangedEvent(int type, qint64 startTime, qint64 len
|
|||||||
const QStringList &data, const QString &fileName, int line)
|
const QStringList &data, const QString &fileName, int line)
|
||||||
{
|
{
|
||||||
const QChar colon = QLatin1Char(':');
|
const QChar colon = QLatin1Char(':');
|
||||||
QString displayName, location, details;
|
QString displayName, eventHashStr, details;
|
||||||
|
|
||||||
emit processingData();
|
emit processingData();
|
||||||
|
|
||||||
if (fileName.isEmpty()) {
|
|
||||||
displayName = tr("<bytecode>");
|
|
||||||
location = QString("--:%1:%2").arg(QString::number(type), data.join(" "));
|
|
||||||
} else {
|
|
||||||
const QString filePath = QUrl(fileName).path();
|
|
||||||
displayName = filePath.mid(filePath.lastIndexOf(QChar('/')) + 1) + colon + QString::number(line);
|
|
||||||
location = fileName+colon+QString::number(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
QmlEventData *newEvent;
|
|
||||||
if (d->m_eventDescriptions.contains(location)) {
|
|
||||||
newEvent = d->m_eventDescriptions[location];
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// generate details string
|
// generate details string
|
||||||
if (data.isEmpty())
|
if (data.isEmpty())
|
||||||
details = tr("Source code not available");
|
details = tr("Source code not available");
|
||||||
@@ -281,14 +389,28 @@ void QmlProfilerEventList::addRangedEvent(int type, qint64 startTime, qint64 len
|
|||||||
details = details.mid(details.lastIndexOf(QChar('/')) + 1);
|
details = details.mid(details.lastIndexOf(QChar('/')) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
newEvent = new QmlEventData();
|
// generate hash
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
displayName = tr("<bytecode>");
|
||||||
|
eventHashStr = QString("--:%1:%2").arg(QString::number(type), details);
|
||||||
|
} else {
|
||||||
|
const QString filePath = QUrl(fileName).path();
|
||||||
|
displayName = filePath.mid(filePath.lastIndexOf(QChar('/')) + 1) + colon + QString::number(line);
|
||||||
|
eventHashStr = QString("%1:%2:%3:%4").arg(fileName, QString::number(line), QString::number(type), details);
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlEventData *newEvent;
|
||||||
|
if (d->m_eventDescriptions.contains(eventHashStr)) {
|
||||||
|
newEvent = d->m_eventDescriptions[eventHashStr];
|
||||||
|
} else {
|
||||||
|
newEvent = new QmlEventData;
|
||||||
newEvent->displayname = displayName;
|
newEvent->displayname = displayName;
|
||||||
newEvent->filename = fileName;
|
newEvent->filename = fileName;
|
||||||
newEvent->location = location;
|
newEvent->eventHashStr = eventHashStr;
|
||||||
newEvent->line = line;
|
newEvent->line = line;
|
||||||
newEvent->eventType = (QmlJsDebugClient::QmlEventType)type;
|
newEvent->eventType = (QmlJsDebugClient::QmlEventType)type;
|
||||||
newEvent->details = details;
|
newEvent->details = details;
|
||||||
d->m_eventDescriptions.insert(location, newEvent);
|
d->m_eventDescriptions.insert(eventHashStr, newEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlEventEndTimeData endTimeData;
|
QmlEventEndTimeData endTimeData;
|
||||||
@@ -311,7 +433,7 @@ void QmlProfilerEventList::addRangedEvent(int type, qint64 startTime, qint64 len
|
|||||||
void QmlProfilerEventList::addV8Event(int depth, const QString &function, const QString &filename, int lineNumber, double totalTime, double selfTime)
|
void QmlProfilerEventList::addV8Event(int depth, const QString &function, const QString &filename, int lineNumber, double totalTime, double selfTime)
|
||||||
{
|
{
|
||||||
QString displayName = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') + QString::number(lineNumber);
|
QString displayName = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') + QString::number(lineNumber);
|
||||||
QV8EventData *newData = 0;
|
QV8EventData *eventData = 0;
|
||||||
|
|
||||||
// time is given in milliseconds, but internally we store it in microseconds
|
// time is given in milliseconds, but internally we store it in microseconds
|
||||||
totalTime *= 1e6;
|
totalTime *= 1e6;
|
||||||
@@ -319,45 +441,65 @@ void QmlProfilerEventList::addV8Event(int depth, const QString &function, const
|
|||||||
|
|
||||||
// cumulate information
|
// cumulate information
|
||||||
foreach (QV8EventData *v8event, d->m_v8EventList) {
|
foreach (QV8EventData *v8event, d->m_v8EventList) {
|
||||||
if (v8event->displayName == displayName && v8event->functionName == function)
|
if (v8event->displayName == displayName && v8event->functionName == function) {
|
||||||
newData = v8event;
|
eventData = v8event;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newData) {
|
if (!eventData) {
|
||||||
newData = new QV8EventData();
|
eventData = new QV8EventData;
|
||||||
newData->displayName = displayName;
|
eventData->displayName = displayName;
|
||||||
newData->filename = filename;
|
eventData->filename = filename;
|
||||||
newData->functionName = function;
|
eventData->functionName = function;
|
||||||
newData->line = lineNumber;
|
eventData->line = lineNumber;
|
||||||
newData->totalTime = totalTime;
|
eventData->totalTime = totalTime;
|
||||||
newData->selfTime = selfTime;
|
eventData->selfTime = selfTime;
|
||||||
d->m_v8EventList << newData;
|
d->m_v8EventList << eventData;
|
||||||
} else {
|
} else {
|
||||||
newData->totalTime += totalTime;
|
eventData->totalTime += totalTime;
|
||||||
newData->selfTime += selfTime;
|
eventData->selfTime += selfTime;
|
||||||
}
|
}
|
||||||
d->m_v8parents[depth] = newData;
|
d->m_v8parents[depth] = eventData;
|
||||||
|
|
||||||
if (depth > 0) {
|
QV8EventData *parentEvent = 0;
|
||||||
QV8EventData* parentEvent = d->m_v8parents.value(depth-1);
|
if (depth == 0) {
|
||||||
if (parentEvent) {
|
parentEvent = &d->m_v8RootEvent;
|
||||||
if (!newData->parentList.contains(parentEvent))
|
|
||||||
newData->parentList << parentEvent;
|
|
||||||
if (!parentEvent->childrenList.contains(newData))
|
|
||||||
parentEvent->childrenList << newData;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d->m_v8MeasuredTime += totalTime;
|
d->m_v8MeasuredTime += totalTime;
|
||||||
}
|
}
|
||||||
|
if (depth > 0 && d->m_v8parents.contains(depth-1)) {
|
||||||
|
parentEvent = d->m_v8parents.value(depth-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentEvent != 0) {
|
||||||
|
if (!eventData->parentHash.contains(parentEvent->displayName)) {
|
||||||
|
QV8EventSub *newParentSub = new QV8EventSub(parentEvent);
|
||||||
|
newParentSub->totalTime = totalTime;
|
||||||
|
|
||||||
|
eventData->parentHash.insert(parentEvent->displayName, newParentSub );
|
||||||
|
} else {
|
||||||
|
QV8EventSub *newParentSub = eventData->parentHash.value(parentEvent->displayName);
|
||||||
|
newParentSub->totalTime += totalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parentEvent->childrenHash.contains(eventData->displayName)) {
|
||||||
|
QV8EventSub *newChildSub = new QV8EventSub(eventData);
|
||||||
|
newChildSub->totalTime = totalTime;
|
||||||
|
|
||||||
|
parentEvent->childrenHash.insert(eventData->displayName, newChildSub);
|
||||||
|
} else {
|
||||||
|
QV8EventSub *newChildSub = parentEvent->childrenHash.value(eventData->displayName);
|
||||||
|
newChildSub->totalTime += totalTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerEventList::QmlProfilerEventListPrivate::collectV8Statistics()
|
void QmlProfilerEventList::QmlProfilerEventListPrivate::collectV8Statistics()
|
||||||
{
|
{
|
||||||
if (!m_v8EventList.isEmpty()) {
|
if (!m_v8EventList.isEmpty()) {
|
||||||
double totalTimes = 0;
|
double totalTimes = m_v8MeasuredTime;
|
||||||
double selfTimes = 0;
|
double selfTimes = 0;
|
||||||
foreach (QV8EventData *v8event, m_v8EventList) {
|
foreach (QV8EventData *v8event, m_v8EventList) {
|
||||||
totalTimes += v8event->totalTime;
|
|
||||||
selfTimes += v8event->selfTime;
|
selfTimes += v8event->selfTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,15 +509,38 @@ void QmlProfilerEventList::QmlProfilerEventListPrivate::collectV8Statistics()
|
|||||||
if (selfTimes == 0)
|
if (selfTimes == 0)
|
||||||
selfTimes = 1;
|
selfTimes = 1;
|
||||||
|
|
||||||
|
// insert root event in eventlist
|
||||||
|
// the +1 ns is to get it on top of the sorted list
|
||||||
|
m_v8RootEvent.totalTime = m_v8MeasuredTime + 1;
|
||||||
|
m_v8RootEvent.selfTime = 0;
|
||||||
|
|
||||||
|
int rootEventIndex = -1;
|
||||||
|
for (int ndx = 0; ndx < m_v8EventList.count(); ndx++)
|
||||||
|
{
|
||||||
|
if (m_v8EventList.at(ndx)->displayName == m_rootEventName) {
|
||||||
|
m_v8RootEvent = *m_v8EventList.at(ndx);
|
||||||
|
rootEventIndex = ndx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rootEventIndex == -1) {
|
||||||
|
rootEventIndex = m_v8EventList.count();
|
||||||
|
QV8EventData *newRootEvent = new QV8EventData;
|
||||||
|
*newRootEvent = m_v8RootEvent;
|
||||||
|
m_v8EventList << newRootEvent;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (QV8EventData *v8event, m_v8EventList) {
|
foreach (QV8EventData *v8event, m_v8EventList) {
|
||||||
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
|
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
|
||||||
v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
|
v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (QV8EventData *v8event, m_v8EventList)
|
foreach (QV8EventData *v8event, m_v8EventList) {
|
||||||
v8event->eventId = index++;
|
v8event->eventId = index++;
|
||||||
}
|
}
|
||||||
|
m_v8RootEvent.eventId = m_v8EventList[rootEventIndex]->eventId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerEventList::setTraceEndTime( qint64 time )
|
void QmlProfilerEventList::setTraceEndTime( qint64 time )
|
||||||
@@ -395,11 +560,52 @@ void QmlProfilerEventList::complete()
|
|||||||
postProcess();
|
postProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerEventList::QmlProfilerEventListPrivate::clearQmlRootEvent()
|
||||||
|
{
|
||||||
|
m_qmlRootEvent.displayname = m_rootEventName;
|
||||||
|
m_qmlRootEvent.filename = QString();
|
||||||
|
m_qmlRootEvent.eventHashStr = m_rootEventName;
|
||||||
|
m_qmlRootEvent.details = m_rootEventDesc;
|
||||||
|
m_qmlRootEvent.line = 01;
|
||||||
|
m_qmlRootEvent.eventType = QmlJsDebugClient::Binding;
|
||||||
|
m_qmlRootEvent.duration = 0;
|
||||||
|
m_qmlRootEvent.calls = 0;
|
||||||
|
m_qmlRootEvent.minTime = 0;
|
||||||
|
m_qmlRootEvent.maxTime = 0;
|
||||||
|
m_qmlRootEvent.timePerCall = 0;
|
||||||
|
m_qmlRootEvent.percentOfTime = 0;
|
||||||
|
m_qmlRootEvent.medianTime = 0;
|
||||||
|
m_qmlRootEvent.eventId = -1;
|
||||||
|
|
||||||
|
qDeleteAll(m_qmlRootEvent.parentHash.values());
|
||||||
|
qDeleteAll(m_qmlRootEvent.childrenHash.values());
|
||||||
|
m_qmlRootEvent.parentHash.clear();
|
||||||
|
m_qmlRootEvent.childrenHash.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlProfilerEventList::QmlProfilerEventListPrivate::clearV8RootEvent()
|
||||||
|
{
|
||||||
|
m_v8RootEvent.displayName = m_rootEventName;
|
||||||
|
m_v8RootEvent.functionName = m_rootEventDesc;
|
||||||
|
m_v8RootEvent.line = -1;
|
||||||
|
m_v8RootEvent.totalTime = 0;
|
||||||
|
m_v8RootEvent.totalPercent = 0;
|
||||||
|
m_v8RootEvent.selfTime = 0;
|
||||||
|
m_v8RootEvent.selfPercent = 0;
|
||||||
|
m_v8RootEvent.eventId = -1;
|
||||||
|
|
||||||
|
qDeleteAll(m_v8RootEvent.parentHash.values());
|
||||||
|
qDeleteAll(m_v8RootEvent.childrenHash.values());
|
||||||
|
m_v8RootEvent.parentHash.clear();
|
||||||
|
m_v8RootEvent.childrenHash.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
|
void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
int fromIndex = findFirstIndex(startTime);
|
int fromIndex = findFirstIndex(startTime);
|
||||||
int toIndex = findLastIndex(endTime);
|
int toIndex = findLastIndex(endTime);
|
||||||
|
double totalTime = 0;
|
||||||
|
|
||||||
// clear existing statistics
|
// clear existing statistics
|
||||||
foreach (QmlEventData *eventDescription, d->m_eventDescriptions.values()) {
|
foreach (QmlEventData *eventDescription, d->m_eventDescriptions.values()) {
|
||||||
@@ -408,11 +614,16 @@ void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
|
|||||||
eventDescription->minTime = d->m_endTimeSortedList.last().endTime;
|
eventDescription->minTime = d->m_endTimeSortedList.last().endTime;
|
||||||
eventDescription->maxTime = 0;
|
eventDescription->maxTime = 0;
|
||||||
eventDescription->medianTime = 0;
|
eventDescription->medianTime = 0;
|
||||||
eventDescription->cumulatedDuration = 0;
|
eventDescription->duration = 0;
|
||||||
eventDescription->parentList.clear();
|
qDeleteAll(eventDescription->parentHash);
|
||||||
eventDescription->childrenList.clear();
|
qDeleteAll(eventDescription->childrenHash);
|
||||||
|
eventDescription->parentHash.clear();
|
||||||
|
eventDescription->childrenHash.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create root event for statistics
|
||||||
|
d->clearQmlRootEvent();
|
||||||
|
|
||||||
// compute parent-child relationship and call count
|
// compute parent-child relationship and call count
|
||||||
QHash<int, QmlEventData*> lastParent;
|
QHash<int, QmlEventData*> lastParent;
|
||||||
for (index = fromIndex; index <= toIndex; index++) {
|
for (index = fromIndex; index <= toIndex; index++) {
|
||||||
@@ -425,35 +636,71 @@ void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
|
|||||||
|
|
||||||
eventDescription->calls++;
|
eventDescription->calls++;
|
||||||
qint64 duration = d->m_startTimeSortedList[index].length;
|
qint64 duration = d->m_startTimeSortedList[index].length;
|
||||||
eventDescription->cumulatedDuration += duration;
|
eventDescription->duration += duration;
|
||||||
if (eventDescription->maxTime < duration)
|
if (eventDescription->maxTime < duration)
|
||||||
eventDescription->maxTime = duration;
|
eventDescription->maxTime = duration;
|
||||||
if (eventDescription->minTime > duration)
|
if (eventDescription->minTime > duration)
|
||||||
eventDescription->minTime = duration;
|
eventDescription->minTime = duration;
|
||||||
|
|
||||||
int level = d->m_startTimeSortedList[index].level;
|
int level = d->m_startTimeSortedList[index].level;
|
||||||
if (level > MIN_LEVEL) {
|
|
||||||
if (lastParent.contains(level-1)) {
|
QmlEventData *parentEvent = &d->m_qmlRootEvent;
|
||||||
QmlEventData *parentEvent = lastParent[level-1];
|
if (level > MIN_LEVEL && lastParent.contains(level-1)) {
|
||||||
if (!eventDescription->parentList.contains(parentEvent))
|
parentEvent = lastParent[level-1];
|
||||||
eventDescription->parentList.append(parentEvent);
|
|
||||||
if (!parentEvent->childrenList.contains(eventDescription))
|
|
||||||
parentEvent->childrenList.append(eventDescription);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!eventDescription->parentHash.contains(parentEvent->eventHashStr)) {
|
||||||
|
QmlEventSub *newParentEvent = new QmlEventSub(parentEvent);
|
||||||
|
newParentEvent->calls = 1;
|
||||||
|
newParentEvent->duration = duration;
|
||||||
|
|
||||||
|
eventDescription->parentHash.insert(parentEvent->eventHashStr, newParentEvent);
|
||||||
|
} else {
|
||||||
|
QmlEventSub *newParentEvent = eventDescription->parentHash.value(parentEvent->eventHashStr);
|
||||||
|
newParentEvent->duration += duration;
|
||||||
|
newParentEvent->calls++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parentEvent->childrenHash.contains(eventDescription->eventHashStr)) {
|
||||||
|
QmlEventSub *newChildEvent = new QmlEventSub(eventDescription);
|
||||||
|
newChildEvent->calls = 1;
|
||||||
|
newChildEvent->duration = duration;
|
||||||
|
|
||||||
|
parentEvent->childrenHash.insert(eventDescription->eventHashStr, newChildEvent);
|
||||||
|
} else {
|
||||||
|
QmlEventSub *newChildEvent = parentEvent->childrenHash.value(eventDescription->eventHashStr);
|
||||||
|
newChildEvent->duration += duration;
|
||||||
|
newChildEvent->calls++;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastParent[level] = eventDescription;
|
lastParent[level] = eventDescription;
|
||||||
|
|
||||||
|
if (level == MIN_LEVEL) {
|
||||||
|
totalTime += duration;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fake rootEvent statistics
|
||||||
|
// the +1 nanosecond is to force it to be on top of the sorted list
|
||||||
|
d->m_qmlRootEvent.duration = totalTime+1;
|
||||||
|
d->m_qmlRootEvent.minTime = totalTime+1;
|
||||||
|
d->m_qmlRootEvent.maxTime = totalTime+1;
|
||||||
|
d->m_qmlRootEvent.medianTime = totalTime+1;
|
||||||
|
if (totalTime > 0)
|
||||||
|
d->m_qmlRootEvent.calls = 1;
|
||||||
|
|
||||||
|
// insert into list
|
||||||
|
QmlEventData *listedRootEvent = d->m_eventDescriptions.value(d->m_rootEventName);
|
||||||
|
if (!listedRootEvent) {
|
||||||
|
listedRootEvent = new QmlEventData;
|
||||||
|
d->m_eventDescriptions.insert(d->m_rootEventName, listedRootEvent);
|
||||||
|
}
|
||||||
|
*listedRootEvent = d->m_qmlRootEvent;
|
||||||
|
|
||||||
// compute percentages
|
// compute percentages
|
||||||
double totalTime = 0;
|
|
||||||
foreach (QmlEventData *binding, d->m_eventDescriptions.values()) {
|
foreach (QmlEventData *binding, d->m_eventDescriptions.values()) {
|
||||||
totalTime += binding->cumulatedDuration;
|
binding->percentOfTime = binding->duration * 100.0 / totalTime;
|
||||||
}
|
binding->timePerCall = binding->calls > 0 ? double(binding->duration) / binding->calls : 0;
|
||||||
|
|
||||||
foreach (QmlEventData *binding, d->m_eventDescriptions.values()) {
|
|
||||||
binding->percentOfTime = binding->cumulatedDuration * 100.0 / totalTime;
|
|
||||||
binding->timePerCall = binding->calls > 0 ? double(binding->cumulatedDuration) / binding->calls : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute median time
|
// compute median time
|
||||||
@@ -841,14 +1088,17 @@ bool QmlProfilerEventList::save(const QString &filename)
|
|||||||
stream.writeStartDocument();
|
stream.writeStartDocument();
|
||||||
|
|
||||||
stream.writeStartElement("trace");
|
stream.writeStartElement("trace");
|
||||||
|
stream.writeAttribute("version", Constants::PROFILER_FILE_VERSION);
|
||||||
|
|
||||||
stream.writeAttribute("traceStart", QString::number(traceStartTime()));
|
stream.writeAttribute("traceStart", QString::number(traceStartTime()));
|
||||||
stream.writeAttribute("traceEnd", QString::number(traceEndTime()));
|
stream.writeAttribute("traceEnd", QString::number(traceEndTime()));
|
||||||
|
|
||||||
stream.writeStartElement("eventData");
|
stream.writeStartElement("eventData");
|
||||||
|
stream.writeAttribute("totalTime", QString::number(d->m_qmlMeasuredTime));
|
||||||
|
|
||||||
foreach (const QmlEventData *eventData, d->m_eventDescriptions.values()) {
|
foreach (const QmlEventData *eventData, d->m_eventDescriptions.values()) {
|
||||||
stream.writeStartElement("event");
|
stream.writeStartElement("event");
|
||||||
stream.writeAttribute("index", QString::number(d->m_eventDescriptions.keys().indexOf(eventData->location)));
|
stream.writeAttribute("index", QString::number(d->m_eventDescriptions.keys().indexOf(eventData->eventHashStr)));
|
||||||
stream.writeTextElement("displayname", eventData->displayname);
|
stream.writeTextElement("displayname", eventData->displayname);
|
||||||
stream.writeTextElement("type", qmlEventType(eventData->eventType));
|
stream.writeTextElement("type", qmlEventType(eventData->eventType));
|
||||||
if (!eventData->filename.isEmpty()) {
|
if (!eventData->filename.isEmpty()) {
|
||||||
@@ -865,12 +1115,13 @@ bool QmlProfilerEventList::save(const QString &filename)
|
|||||||
stream.writeStartElement("range");
|
stream.writeStartElement("range");
|
||||||
stream.writeAttribute("startTime", QString::number(rangedEvent.startTime));
|
stream.writeAttribute("startTime", QString::number(rangedEvent.startTime));
|
||||||
stream.writeAttribute("duration", QString::number(rangedEvent.length));
|
stream.writeAttribute("duration", QString::number(rangedEvent.length));
|
||||||
stream.writeAttribute("eventIndex", QString::number(d->m_eventDescriptions.keys().indexOf(rangedEvent.description->location)));
|
stream.writeAttribute("eventIndex", QString::number(d->m_eventDescriptions.keys().indexOf(rangedEvent.description->eventHashStr)));
|
||||||
stream.writeEndElement();
|
stream.writeEndElement();
|
||||||
}
|
}
|
||||||
stream.writeEndElement(); // eventList
|
stream.writeEndElement(); // eventList
|
||||||
|
|
||||||
stream.writeStartElement("v8profile"); // v8 profiler output
|
stream.writeStartElement("v8profile"); // v8 profiler output
|
||||||
|
stream.writeAttribute("totalTime", QString::number(d->m_v8MeasuredTime));
|
||||||
foreach (QV8EventData *v8event, d->m_v8EventList) {
|
foreach (QV8EventData *v8event, d->m_v8EventList) {
|
||||||
stream.writeStartElement("event");
|
stream.writeStartElement("event");
|
||||||
stream.writeAttribute("index", QString::number(d->m_v8EventList.indexOf(v8event)));
|
stream.writeAttribute("index", QString::number(d->m_v8EventList.indexOf(v8event)));
|
||||||
@@ -882,13 +1133,20 @@ bool QmlProfilerEventList::save(const QString &filename)
|
|||||||
}
|
}
|
||||||
stream.writeTextElement("totalTime", QString::number(v8event->totalTime));
|
stream.writeTextElement("totalTime", QString::number(v8event->totalTime));
|
||||||
stream.writeTextElement("selfTime", QString::number(v8event->selfTime));
|
stream.writeTextElement("selfTime", QString::number(v8event->selfTime));
|
||||||
if (!v8event->childrenList.isEmpty()) {
|
if (!v8event->childrenHash.isEmpty()) {
|
||||||
stream.writeStartElement("childrenEvents");
|
stream.writeStartElement("childrenEvents");
|
||||||
QStringList childrenIndexes;
|
QStringList childrenIndexes;
|
||||||
foreach (QV8EventData *v8child, v8event->childrenList) {
|
QStringList childrenTimes;
|
||||||
childrenIndexes << QString::number(d->m_v8EventList.indexOf(v8child));
|
QStringList parentTimes;
|
||||||
|
foreach (QV8EventSub *v8child, v8event->childrenHash.values()) {
|
||||||
|
childrenIndexes << QString::number(v8child->reference->eventId);
|
||||||
|
childrenTimes << QString::number(v8child->totalTime);
|
||||||
|
parentTimes << QString::number(d->m_v8EventList[v8child->reference->eventId]->parentHash[v8event->displayName]->totalTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.writeAttribute("list", childrenIndexes.join(QString(", ")));
|
stream.writeAttribute("list", childrenIndexes.join(QString(", ")));
|
||||||
|
stream.writeAttribute("childrenTimes", childrenTimes.join(QString(", ")));
|
||||||
|
stream.writeAttribute("parentTimes", parentTimes.join(QString(", ")));
|
||||||
stream.writeEndElement();
|
stream.writeEndElement();
|
||||||
}
|
}
|
||||||
stream.writeEndElement();
|
stream.writeEndElement();
|
||||||
@@ -936,12 +1194,20 @@ void QmlProfilerEventList::load()
|
|||||||
QmlEventData *currentEvent = 0;
|
QmlEventData *currentEvent = 0;
|
||||||
QHash <int, QV8EventData *> v8eventBuffer;
|
QHash <int, QV8EventData *> v8eventBuffer;
|
||||||
QHash <int, QString> childrenIndexes;
|
QHash <int, QString> childrenIndexes;
|
||||||
|
QHash <int, QString> childrenTimes;
|
||||||
|
QHash <int, QString> parentTimes;
|
||||||
QV8EventData *v8event = 0;
|
QV8EventData *v8event = 0;
|
||||||
bool startTimesAreSorted = true;
|
bool startTimesAreSorted = true;
|
||||||
|
bool validVersion = true;
|
||||||
|
|
||||||
|
// time computation
|
||||||
|
d->m_v8MeasuredTime = 0;
|
||||||
|
d->m_qmlMeasuredTime = 0;
|
||||||
|
double cumulatedV8Time = 0;
|
||||||
|
|
||||||
QXmlStreamReader stream(&file);
|
QXmlStreamReader stream(&file);
|
||||||
|
|
||||||
while (!stream.atEnd() && !stream.hasError()) {
|
while (validVersion && !stream.atEnd() && !stream.hasError()) {
|
||||||
QXmlStreamReader::TokenType token = stream.readNext();
|
QXmlStreamReader::TokenType token = stream.readNext();
|
||||||
QString elementName = stream.name().toString();
|
QString elementName = stream.name().toString();
|
||||||
switch (token) {
|
switch (token) {
|
||||||
@@ -949,6 +1215,10 @@ void QmlProfilerEventList::load()
|
|||||||
case QXmlStreamReader::StartElement : {
|
case QXmlStreamReader::StartElement : {
|
||||||
if (elementName == "trace") {
|
if (elementName == "trace") {
|
||||||
QXmlStreamAttributes attributes = stream.attributes();
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
|
if (attributes.hasAttribute("version"))
|
||||||
|
validVersion = attributes.value("version").toString() == Constants::PROFILER_FILE_VERSION;
|
||||||
|
else
|
||||||
|
validVersion = false;
|
||||||
if (attributes.hasAttribute("traceStart"))
|
if (attributes.hasAttribute("traceStart"))
|
||||||
setTraceStartTime(attributes.value("traceStart").toString().toLongLong());
|
setTraceStartTime(attributes.value("traceStart").toString().toLongLong());
|
||||||
if (attributes.hasAttribute("traceEnd"))
|
if (attributes.hasAttribute("traceEnd"))
|
||||||
@@ -956,10 +1226,25 @@ void QmlProfilerEventList::load()
|
|||||||
}
|
}
|
||||||
if (elementName == "eventData" && !readingV8Events) {
|
if (elementName == "eventData" && !readingV8Events) {
|
||||||
readingQmlEvents = true;
|
readingQmlEvents = true;
|
||||||
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
|
if (attributes.hasAttribute("totalTime"))
|
||||||
|
d->m_qmlMeasuredTime = attributes.value("totalTime").toString().toDouble();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (elementName == "v8profile" && !readingQmlEvents) {
|
if (elementName == "v8profile" && !readingQmlEvents) {
|
||||||
readingV8Events = true;
|
readingV8Events = true;
|
||||||
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
|
if (attributes.hasAttribute("totalTime"))
|
||||||
|
d->m_v8MeasuredTime = attributes.value("totalTime").toString().toDouble();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementName == "trace") {
|
||||||
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
|
if (attributes.hasAttribute("traceStart"))
|
||||||
|
setTraceStartTime(attributes.value("traceStart").toString().toLongLong());
|
||||||
|
if (attributes.hasAttribute("traceEnd"))
|
||||||
|
setTraceEndTime(attributes.value("traceEnd").toString().toLongLong());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementName == "range") {
|
if (elementName == "range") {
|
||||||
@@ -972,7 +1257,7 @@ void QmlProfilerEventList::load()
|
|||||||
if (attributes.hasAttribute("eventIndex")) {
|
if (attributes.hasAttribute("eventIndex")) {
|
||||||
int ndx = attributes.value("eventIndex").toString().toInt();
|
int ndx = attributes.value("eventIndex").toString().toInt();
|
||||||
if (!descriptionBuffer.value(ndx))
|
if (!descriptionBuffer.value(ndx))
|
||||||
descriptionBuffer[ndx] = new QmlEventData();
|
descriptionBuffer[ndx] = new QmlEventData;
|
||||||
rangedEvent.description = descriptionBuffer.value(ndx);
|
rangedEvent.description = descriptionBuffer.value(ndx);
|
||||||
}
|
}
|
||||||
rangedEvent.endTimeIndex = d->m_endTimeSortedList.length();
|
rangedEvent.endTimeIndex = d->m_endTimeSortedList.length();
|
||||||
@@ -996,7 +1281,7 @@ void QmlProfilerEventList::load()
|
|||||||
if (attributes.hasAttribute("index")) {
|
if (attributes.hasAttribute("index")) {
|
||||||
int ndx = attributes.value("index").toString().toInt();
|
int ndx = attributes.value("index").toString().toInt();
|
||||||
if (!descriptionBuffer.value(ndx))
|
if (!descriptionBuffer.value(ndx))
|
||||||
descriptionBuffer[ndx] = new QmlEventData();
|
descriptionBuffer[ndx] = new QmlEventData;
|
||||||
currentEvent = descriptionBuffer[ndx];
|
currentEvent = descriptionBuffer[ndx];
|
||||||
} else {
|
} else {
|
||||||
currentEvent = 0;
|
currentEvent = 0;
|
||||||
@@ -1055,9 +1340,16 @@ void QmlProfilerEventList::load()
|
|||||||
|
|
||||||
if (elementName == "childrenEvents") {
|
if (elementName == "childrenEvents") {
|
||||||
QXmlStreamAttributes attributes = stream.attributes();
|
QXmlStreamAttributes attributes = stream.attributes();
|
||||||
|
int eventIndex = v8eventBuffer.key(v8event);
|
||||||
if (attributes.hasAttribute("list")) {
|
if (attributes.hasAttribute("list")) {
|
||||||
// store for later parsing (we haven't read all the events yet)
|
// store for later parsing (we haven't read all the events yet)
|
||||||
childrenIndexes[v8eventBuffer.key(v8event)] = attributes.value("list").toString();
|
childrenIndexes[eventIndex] = attributes.value("list").toString();
|
||||||
|
}
|
||||||
|
if (attributes.hasAttribute("childrenTimes")) {
|
||||||
|
childrenTimes[eventIndex] = attributes.value("childrenTimes").toString();
|
||||||
|
}
|
||||||
|
if (attributes.hasAttribute("parentTimes")) {
|
||||||
|
parentTimes[eventIndex] = attributes.value("parentTimes").toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,6 +1380,7 @@ void QmlProfilerEventList::load()
|
|||||||
|
|
||||||
if (elementName == "totalTime") {
|
if (elementName == "totalTime") {
|
||||||
v8event->totalTime = readData.toDouble();
|
v8event->totalTime = readData.toDouble();
|
||||||
|
cumulatedV8Time += v8event->totalTime;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,10 +1419,22 @@ void QmlProfilerEventList::load()
|
|||||||
|
|
||||||
stream.clear();
|
stream.clear();
|
||||||
|
|
||||||
|
if (!validVersion) {
|
||||||
|
clear();
|
||||||
|
emit countChanged();
|
||||||
|
emit dataReady();
|
||||||
|
emit error(tr("Invalid version of QmlProfiler trace file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// backwards compatibility
|
||||||
|
if (d->m_v8MeasuredTime == 0)
|
||||||
|
d->m_v8MeasuredTime = cumulatedV8Time;
|
||||||
|
|
||||||
// move the buffered data to the details cache
|
// move the buffered data to the details cache
|
||||||
foreach (QmlEventData *desc, descriptionBuffer.values()) {
|
foreach (QmlEventData *desc, descriptionBuffer.values()) {
|
||||||
QString location = QString("%1:%2:%3").arg(QString::number(desc->eventType), desc->displayname, desc->details);
|
QString location = QString("%1:%2:%3").arg(QString::number(desc->eventType), desc->displayname, desc->details);
|
||||||
desc->location = location;
|
desc->eventHashStr = location;
|
||||||
d->m_eventDescriptions[location] = desc;
|
d->m_eventDescriptions[location] = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1145,12 +1450,20 @@ void QmlProfilerEventList::load()
|
|||||||
|
|
||||||
// find v8events' children and parents
|
// find v8events' children and parents
|
||||||
foreach (int parentIndex, childrenIndexes.keys()) {
|
foreach (int parentIndex, childrenIndexes.keys()) {
|
||||||
QStringList childrenStrings = childrenIndexes.value(parentIndex).split((","));
|
QStringList childrenStrings = childrenIndexes.value(parentIndex).split(",");
|
||||||
foreach (const QString &childString, childrenStrings) {
|
QStringList childrenTimesStrings = childrenTimes.value(parentIndex).split(", ");
|
||||||
int childIndex = childString.toInt();
|
QStringList parentTimesStrings = parentTimes.value(parentIndex).split(", ");
|
||||||
|
for (int ndx = 0; ndx < childrenStrings.count(); ndx++) {
|
||||||
|
int childIndex = childrenStrings[ndx].toInt();
|
||||||
if (v8eventBuffer.value(childIndex)) {
|
if (v8eventBuffer.value(childIndex)) {
|
||||||
v8eventBuffer[parentIndex]->childrenList << v8eventBuffer[childIndex];
|
QV8EventSub *newChild = new QV8EventSub(v8eventBuffer[childIndex]);
|
||||||
v8eventBuffer[childIndex]->parentList << v8eventBuffer[parentIndex];
|
QV8EventSub *newParent = new QV8EventSub(v8eventBuffer[parentIndex]);
|
||||||
|
if (childrenTimesStrings.count() > ndx)
|
||||||
|
newChild->totalTime = childrenTimesStrings[ndx].toDouble();
|
||||||
|
if (parentTimesStrings.count() > ndx)
|
||||||
|
newParent->totalTime = parentTimesStrings[ndx].toDouble();
|
||||||
|
v8eventBuffer[parentIndex]->childrenHash.insert(newChild->reference->displayName, newChild);
|
||||||
|
v8eventBuffer[childIndex]->parentHash.insert(newParent->reference->displayName, newParent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,18 +41,23 @@
|
|||||||
|
|
||||||
namespace QmlJsDebugClient {
|
namespace QmlJsDebugClient {
|
||||||
|
|
||||||
|
struct QmlEventSub;
|
||||||
|
struct QV8EventSub;
|
||||||
|
|
||||||
struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
||||||
{
|
{
|
||||||
QmlEventData():line(-1),cumulatedDuration(0),calls(0),eventId(-1){}
|
QmlEventData();
|
||||||
|
~QmlEventData();
|
||||||
|
|
||||||
QString displayname;
|
QString displayname;
|
||||||
QString filename;
|
QString filename;
|
||||||
QString location;
|
QString eventHashStr;
|
||||||
QString details;
|
QString details;
|
||||||
int line;
|
int line;
|
||||||
QmlJsDebugClient::QmlEventType eventType;
|
QmlJsDebugClient::QmlEventType eventType;
|
||||||
QList< QmlEventData *> parentList;
|
QHash <QString, QmlEventSub *> parentHash;
|
||||||
QList< QmlEventData *> childrenList;
|
QHash <QString, QmlEventSub *> childrenHash;
|
||||||
qint64 cumulatedDuration;
|
qint64 duration;
|
||||||
qint64 calls;
|
qint64 calls;
|
||||||
qint64 minTime;
|
qint64 minTime;
|
||||||
qint64 maxTime;
|
qint64 maxTime;
|
||||||
@@ -60,10 +65,23 @@ struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
|||||||
double percentOfTime;
|
double percentOfTime;
|
||||||
qint64 medianTime;
|
qint64 medianTime;
|
||||||
int eventId;
|
int eventId;
|
||||||
|
|
||||||
|
QmlEventData &operator=(const QmlEventData &ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QMLJSDEBUGCLIENT_EXPORT QmlEventSub {
|
||||||
|
QmlEventSub(QmlEventData *from) : reference(from), duration(0), calls(0) {}
|
||||||
|
QmlEventSub(QmlEventSub *from) : reference(from->reference), duration(from->duration), calls(from->calls) {}
|
||||||
|
QmlEventData *reference;
|
||||||
|
qint64 duration;
|
||||||
|
qint64 calls;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
||||||
{
|
{
|
||||||
|
QV8EventData();
|
||||||
|
~QV8EventData();
|
||||||
|
|
||||||
QString displayName;
|
QString displayName;
|
||||||
QString filename;
|
QString filename;
|
||||||
QString functionName;
|
QString functionName;
|
||||||
@@ -72,9 +90,19 @@ struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
|||||||
double totalPercent;
|
double totalPercent;
|
||||||
double selfTime;
|
double selfTime;
|
||||||
double selfPercent;
|
double selfPercent;
|
||||||
QList< QV8EventData *> parentList;
|
QHash <QString, QV8EventSub *> parentHash;
|
||||||
QList< QV8EventData *> childrenList;
|
QHash <QString, QV8EventSub *> childrenHash;
|
||||||
int eventId;
|
int eventId;
|
||||||
|
|
||||||
|
QV8EventData &operator=(const QV8EventData &ref);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QMLJSDEBUGCLIENT_EXPORT QV8EventSub {
|
||||||
|
QV8EventSub(QV8EventData *from) : reference(from), totalTime(0) {}
|
||||||
|
QV8EventSub(QV8EventSub *from) : reference(from->reference), totalTime(from->totalTime) {}
|
||||||
|
|
||||||
|
QV8EventData *reference;
|
||||||
|
qint64 totalTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef QHash<QString, QmlEventData *> QmlEventHash;
|
typedef QHash<QString, QmlEventData *> QmlEventHash;
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ function drawData(canvas, ctxt, region)
|
|||||||
|
|
||||||
function drawTimeBar(canvas, ctxt, region)
|
function drawTimeBar(canvas, ctxt, region)
|
||||||
{
|
{
|
||||||
|
if (!qmlEventList)
|
||||||
|
return;
|
||||||
|
|
||||||
var width = canvas.width;
|
var width = canvas.width;
|
||||||
var height = 10;
|
var height = 10;
|
||||||
var startTime = qmlEventList.traceStartTime();
|
var startTime = qmlEventList.traceStartTime();
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
data(LineRole).toInt() < other.data(LineRole).toInt() :
|
data(LineRole).toInt() < other.data(LineRole).toInt() :
|
||||||
data(FilenameRole).toString() < other.data(FilenameRole).toString();
|
data(FilenameRole).toString() < other.data(FilenameRole).toString();
|
||||||
} else {
|
} else {
|
||||||
return data().toString() < other.data().toString();
|
return data().toString().toLower() < other.data().toString().toLower();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +196,6 @@ public:
|
|||||||
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
|
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
|
||||||
void buildV8ModelFromList( const QV8EventDescriptions &list );
|
void buildV8ModelFromList( const QV8EventDescriptions &list );
|
||||||
int getFieldCount();
|
int getFieldCount();
|
||||||
QString displayTime(double time) const;
|
|
||||||
QString nameForType(int typeNumber) const;
|
|
||||||
|
|
||||||
QString textForItem(QStandardItem *item, bool recursive) const;
|
QString textForItem(QStandardItem *item, bool recursive) const;
|
||||||
|
|
||||||
@@ -282,8 +280,6 @@ void QmlProfilerEventsMainView::setViewType(ViewTypes type)
|
|||||||
setFieldViewable(MinTime, true);
|
setFieldViewable(MinTime, true);
|
||||||
setFieldViewable(MedianTime, true);
|
setFieldViewable(MedianTime, true);
|
||||||
setFieldViewable(Details, true);
|
setFieldViewable(Details, true);
|
||||||
setFieldViewable(Parents, false);
|
|
||||||
setFieldViewable(Children, false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case V8ProfileView: {
|
case V8ProfileView: {
|
||||||
@@ -300,8 +296,6 @@ void QmlProfilerEventsMainView::setViewType(ViewTypes type)
|
|||||||
setFieldViewable(MinTime, false);
|
setFieldViewable(MinTime, false);
|
||||||
setFieldViewable(MedianTime, false);
|
setFieldViewable(MedianTime, false);
|
||||||
setFieldViewable(Details, true);
|
setFieldViewable(Details, true);
|
||||||
setFieldViewable(Parents, false);
|
|
||||||
setFieldViewable(Children, false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
@@ -358,7 +352,7 @@ int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
|
|||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i=0; i < m_fieldShown.count(); ++i)
|
for (int i=0; i < m_fieldShown.count(); ++i)
|
||||||
if (m_fieldShown[i] && i != Parents && i != Children)
|
if (m_fieldShown[i])
|
||||||
count++;
|
count++;
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -372,12 +366,8 @@ void QmlProfilerEventsMainView::buildModel()
|
|||||||
else
|
else
|
||||||
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
|
||||||
|
|
||||||
bool hasBranches = d->m_fieldShown[Parents] || d->m_fieldShown[Children];
|
setRootIsDecorated(false);
|
||||||
setRootIsDecorated(hasBranches);
|
|
||||||
|
|
||||||
setSortingEnabled(true);
|
setSortingEnabled(true);
|
||||||
|
|
||||||
if (!hasBranches)
|
|
||||||
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
|
sortByColumn(d->m_firstNumericColumn,Qt::DescendingOrder);
|
||||||
|
|
||||||
expandAll();
|
expandAll();
|
||||||
@@ -415,8 +405,8 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_fieldShown[TotalDuration]) {
|
if (m_fieldShown[TotalDuration]) {
|
||||||
newRow << new EventsViewItem(displayTime(binding->cumulatedDuration));
|
newRow << new EventsViewItem(displayTime(binding->duration));
|
||||||
newRow.last()->setData(QVariant(binding->cumulatedDuration));
|
newRow.last()->setData(QVariant(binding->duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_fieldShown[CallCount]) {
|
if (m_fieldShown[CallCount]) {
|
||||||
@@ -457,27 +447,13 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
|||||||
item->setEditable(false);
|
item->setEditable(false);
|
||||||
|
|
||||||
// metadata
|
// metadata
|
||||||
newRow.at(0)->setData(QVariant(binding->location),LocationRole);
|
newRow.at(0)->setData(QVariant(binding->eventHashStr),EventHashStrRole);
|
||||||
newRow.at(0)->setData(QVariant(binding->filename),FilenameRole);
|
newRow.at(0)->setData(QVariant(binding->filename),FilenameRole);
|
||||||
newRow.at(0)->setData(QVariant(binding->line),LineRole);
|
newRow.at(0)->setData(QVariant(binding->line),LineRole);
|
||||||
newRow.at(0)->setData(QVariant(binding->eventId),EventIdRole);
|
newRow.at(0)->setData(QVariant(binding->eventId),EventIdRole);
|
||||||
|
|
||||||
// append
|
// append
|
||||||
parentItem->appendRow(newRow);
|
parentItem->appendRow(newRow);
|
||||||
|
|
||||||
if (m_fieldShown[Parents] && !binding->parentList.isEmpty()) {
|
|
||||||
QmlEventDescriptions newParentList(visitedFunctionsList);
|
|
||||||
newParentList.append(binding);
|
|
||||||
|
|
||||||
buildModelFromList(binding->parentList, newRow.at(0), newParentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_fieldShown[Children] && !binding->childrenList.isEmpty()) {
|
|
||||||
QmlEventDescriptions newChildrenList(visitedFunctionsList);
|
|
||||||
newChildrenList.append(binding);
|
|
||||||
|
|
||||||
buildModelFromList(binding->childrenList, newRow.at(0), newChildrenList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,6 +499,7 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFr
|
|||||||
item->setEditable(false);
|
item->setEditable(false);
|
||||||
|
|
||||||
// metadata
|
// metadata
|
||||||
|
newRow.at(0)->setData(QString("%1:%2").arg(v8event->filename, QString::number(v8event->line)), EventHashStrRole);
|
||||||
newRow.at(0)->setData(QVariant(v8event->filename), FilenameRole);
|
newRow.at(0)->setData(QVariant(v8event->filename), FilenameRole);
|
||||||
newRow.at(0)->setData(QVariant(v8event->line), LineRole);
|
newRow.at(0)->setData(QVariant(v8event->line), LineRole);
|
||||||
newRow.at(0)->setData(QVariant(v8event->eventId), EventIdRole);
|
newRow.at(0)->setData(QVariant(v8event->eventId), EventIdRole);
|
||||||
@@ -533,14 +510,14 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::displayTime(double time) const
|
QString QmlProfilerEventsMainView::displayTime(double time)
|
||||||
{
|
{
|
||||||
if (time < 1e6)
|
if (time < 1e6)
|
||||||
return QString::number(time/1e3,'f',3) + QString::fromWCharArray(L" \u03BCs");
|
return QString::number(time/1e3,'f',3) + trUtf8(" \u03BCs");
|
||||||
if (time < 1e9)
|
if (time < 1e9)
|
||||||
return QString::number(time/1e6,'f',3) + QLatin1String(" ms");
|
return QString::number(time/1e6,'f',3) + tr(" ms");
|
||||||
|
|
||||||
return QString::number(time/1e9,'f',3) + QLatin1String(" s");
|
return QString::number(time/1e9,'f',3) + tr(" s");
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlProfilerEventsMainView::nameForType(int typeNumber)
|
QString QmlProfilerEventsMainView::nameForType(int typeNumber)
|
||||||
@@ -719,24 +696,36 @@ void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
|
|||||||
if (isV8) {
|
if (isV8) {
|
||||||
QmlJsDebugClient::QV8EventData *v8event = m_eventList->v8EventDescription(eventId);
|
QmlJsDebugClient::QV8EventData *v8event = m_eventList->v8EventDescription(eventId);
|
||||||
if (v8event) {
|
if (v8event) {
|
||||||
if (isChildren)
|
if (isChildren) {
|
||||||
rebuildTree((QObject *)&v8event->childrenList);
|
QList <QmlJsDebugClient::QV8EventSub *> childrenList = v8event->childrenHash.values();
|
||||||
else
|
rebuildTree((QObject *)&childrenList);
|
||||||
rebuildTree((QObject *)&v8event->parentList);
|
}
|
||||||
|
else {
|
||||||
|
QList <QmlJsDebugClient::QV8EventSub *> parentList = v8event->parentHash.values();
|
||||||
|
rebuildTree((QObject *)&parentList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QmlJsDebugClient::QmlEventData *qmlEvent = m_eventList->eventDescription(eventId);
|
QmlJsDebugClient::QmlEventData *qmlEvent = m_eventList->eventDescription(eventId);
|
||||||
if (qmlEvent) {
|
if (qmlEvent) {
|
||||||
if (isChildren)
|
if (isChildren) {
|
||||||
rebuildTree((QObject *)&qmlEvent->childrenList);
|
QList <QmlJsDebugClient::QmlEventSub *> childrenList = qmlEvent->childrenHash.values();
|
||||||
else
|
rebuildTree((QObject *)&childrenList);
|
||||||
rebuildTree((QObject *)&qmlEvent->parentList);
|
}
|
||||||
|
else {
|
||||||
|
QList <QmlJsDebugClient::QmlEventSub *> parentList = qmlEvent->parentHash.values();
|
||||||
|
rebuildTree((QObject *)&parentList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHeader();
|
updateHeader();
|
||||||
resizeColumnToContents(0);
|
resizeColumnToContents(0);
|
||||||
setSortingEnabled(true);
|
setSortingEnabled(true);
|
||||||
|
if (isV8)
|
||||||
|
sortByColumn(1);
|
||||||
|
else
|
||||||
|
sortByColumn(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
||||||
@@ -747,8 +736,8 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
|||||||
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
|
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
|
||||||
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
|
||||||
|
|
||||||
QList <QmlEventData *> *qmlList = static_cast< QList <QmlEventData *> *>(eventList);
|
QList <QmlEventSub *> *qmlList = static_cast< QList <QmlEventSub *> *>(eventList);
|
||||||
QList <QV8EventData *> *v8List = static_cast< QList <QV8EventData *> *>(eventList);
|
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(eventList);
|
||||||
|
|
||||||
int listLength;
|
int listLength;
|
||||||
if (!isV8)
|
if (!isV8)
|
||||||
@@ -759,17 +748,23 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
|||||||
for (int index=0; index < listLength; index++) {
|
for (int index=0; index < listLength; index++) {
|
||||||
QList<QStandardItem *> newRow;
|
QList<QStandardItem *> newRow;
|
||||||
if (!isV8) {
|
if (!isV8) {
|
||||||
QmlEventData *event = qmlList->at(index);
|
QmlEventSub *event = qmlList->at(index);
|
||||||
|
|
||||||
newRow << new QStandardItem(event->displayname);
|
newRow << new EventsViewItem(event->reference->displayname);
|
||||||
newRow << new QStandardItem(QmlProfilerEventsMainView::nameForType(event->eventType));
|
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
|
||||||
newRow << new QStandardItem(event->details);
|
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
|
||||||
newRow.at(0)->setData(QVariant(event->eventId), EventIdRole);
|
newRow << new EventsViewItem(QString::number(event->calls));
|
||||||
|
newRow << new EventsViewItem(event->reference->details);
|
||||||
|
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||||
|
newRow.at(2)->setData(QVariant(event->duration));
|
||||||
|
newRow.at(3)->setData(QVariant(event->calls));
|
||||||
} else {
|
} else {
|
||||||
QV8EventData *event = v8List->at(index);
|
QV8EventSub *event = v8List->at(index);
|
||||||
newRow << new QStandardItem(event->displayName);
|
newRow << new EventsViewItem(event->reference->displayName);
|
||||||
newRow << new QStandardItem(event->functionName);
|
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->totalTime));
|
||||||
newRow.at(0)->setData(QVariant(event->eventId), EventIdRole);
|
newRow << new EventsViewItem(event->reference->functionName);
|
||||||
|
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||||
|
newRow.at(1)->setData(QVariant(event->totalTime));
|
||||||
}
|
}
|
||||||
foreach (QStandardItem *item, newRow)
|
foreach (QStandardItem *item, newRow)
|
||||||
item->setEditable(false);
|
item->setEditable(false);
|
||||||
@@ -797,9 +792,9 @@ void QmlProfilerEventsParentsAndChildrenView::updateHeader()
|
|||||||
|
|
||||||
if (treeModel()) {
|
if (treeModel()) {
|
||||||
if (isV8)
|
if (isV8)
|
||||||
treeModel()->setColumnCount(2);
|
|
||||||
else
|
|
||||||
treeModel()->setColumnCount(3);
|
treeModel()->setColumnCount(3);
|
||||||
|
else
|
||||||
|
treeModel()->setColumnCount(5);
|
||||||
|
|
||||||
int columnIndex = 0;
|
int columnIndex = 0;
|
||||||
if (isChildren)
|
if (isChildren)
|
||||||
@@ -810,6 +805,11 @@ void QmlProfilerEventsParentsAndChildrenView::updateHeader()
|
|||||||
if (!isV8)
|
if (!isV8)
|
||||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Type")));
|
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Type")));
|
||||||
|
|
||||||
|
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Total Time")));
|
||||||
|
|
||||||
|
if (!isV8)
|
||||||
|
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Calls")));
|
||||||
|
|
||||||
if (isChildren)
|
if (isChildren)
|
||||||
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Callee Description")));
|
treeModel()->setHeaderData(columnIndex++, Qt::Horizontal, QVariant(tr("Callee Description")));
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ typedef QHash<QString, QmlJsDebugClient::QmlEventData *> QmlEventHash;
|
|||||||
typedef QList<QmlJsDebugClient::QmlEventData *> QmlEventList;
|
typedef QList<QmlJsDebugClient::QmlEventData *> QmlEventList;
|
||||||
|
|
||||||
enum ItemRole {
|
enum ItemRole {
|
||||||
LocationRole = Qt::UserRole+1,
|
EventHashStrRole = Qt::UserRole+1,
|
||||||
FilenameRole = Qt::UserRole+2,
|
FilenameRole = Qt::UserRole+2,
|
||||||
LineRole = Qt::UserRole+3,
|
LineRole = Qt::UserRole+3,
|
||||||
EventIdRole = Qt::UserRole+4
|
EventIdRole = Qt::UserRole+4
|
||||||
@@ -108,8 +108,6 @@ public:
|
|||||||
MinTime,
|
MinTime,
|
||||||
MedianTime,
|
MedianTime,
|
||||||
Details,
|
Details,
|
||||||
Parents,
|
|
||||||
Children,
|
|
||||||
|
|
||||||
MaxFields
|
MaxFields
|
||||||
};
|
};
|
||||||
@@ -135,6 +133,7 @@ public:
|
|||||||
void copyTableToClipboard() const;
|
void copyTableToClipboard() const;
|
||||||
void copyRowToClipboard() const;
|
void copyRowToClipboard() const;
|
||||||
|
|
||||||
|
static QString displayTime(double time);
|
||||||
static QString nameForType(int typeNumber);
|
static QString nameForType(int typeNumber);
|
||||||
|
|
||||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||||
|
|||||||
Reference in New Issue
Block a user