QmlProfiler: Refactor

The code of the qmlprofiler client has become a bit too complex,
this patch reorganizes the modules in a more sensible way,
having the modules communicate with each other through a
state machine instead of the excess of signals and slots
from before.

Change-Id: I76f7313779888a1bd07a1cdb1acbf2e47aacf42a
Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
Christiaan Janssen
2012-02-24 10:47:17 +01:00
parent d207165f6a
commit b7304e2f2e
47 changed files with 4742 additions and 3896 deletions

View File

@@ -7,11 +7,11 @@ contains(CONFIG, dll) {
INCLUDEPATH += $$PWD/..
HEADERS += \
$$PWD/qmlprofilereventlocation.h \
$$PWD/qdeclarativedebugclient.h \
$$PWD/qdeclarativeenginedebug.h \
$$PWD/qdeclarativeoutputparser.h \
$$PWD/qmljsdebugclient_global.h \
$$PWD/qmlprofilereventlist.h \
$$PWD/qmlprofilereventtypes.h \
$$PWD/qmlprofilertraceclient.h \
$$PWD/qpacketprotocol.h \
@@ -23,7 +23,6 @@ SOURCES += \
$$PWD/qdeclarativedebugclient.cpp \
$$PWD/qdeclarativeenginedebug.cpp \
$$PWD/qdeclarativeoutputparser.cpp \
$$PWD/qmlprofilereventlist.cpp \
$$PWD/qmlprofilertraceclient.cpp \
$$PWD/qpacketprotocol.cpp \
$$PWD/qv8profilerclient.cpp \

View File

@@ -11,6 +11,3 @@ OTHER_FILES += \
qmljsdebugclient.pri \
qmljsdebugclient-lib.pri
HEADERS += \
qmlprofilereventlocation.h

View File

@@ -24,7 +24,7 @@ DynamicLibrary {
"qdeclarativeoutputparser.h",
"qmljsdebugclient_global.h",
"qmljsdebugclientconstants.h",
"qmlprofilereventlist.h",
"qmlprofilereventlocation.h",
"qmlprofilertraceclient.cpp",
"qpacketprotocol.cpp",
"qv8profilerclient.cpp",
@@ -36,7 +36,6 @@ DynamicLibrary {
"qmlprofilertraceclient.h",
"qpacketprotocol.h",
"qdebugmessageclient.cpp",
"qmlprofilereventlist.cpp",
"qdebugmessageclient.h"
]

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,8 @@
#include "qmljsdebugclient_global.h"
#include <QString>
namespace QmlJsDebugClient {
struct QMLJSDEBUGCLIENT_EXPORT QmlEventLocation

View File

@@ -33,8 +33,6 @@
#ifndef QMLPROFILEREVENTTYPES_H
#define QMLPROFILEREVENTTYPES_H
#include <QString>
namespace QmlJsDebugClient {
enum QmlEventType {
@@ -47,8 +45,15 @@ enum QmlEventType {
MaximumQmlEventType
};
QString qmlEventType(QmlEventType typeEnum);
QmlEventType qmlEventType(const QString &typeString);
namespace Constants {
const char TYPE_PAINTING_STR[] = "Painting";
const char TYPE_COMPILING_STR[] = "Compiling";
const char TYPE_CREATING_STR[] = "Creating";
const char TYPE_BINDING_STR[] = "Binding";
const char TYPE_HANDLINGSIGNAL_STR[] = "HandlingSignal";
const char PROFILER_FILE_VERSION[] = "1.02";
const int QML_MIN_LEVEL = 1;
}
} // namespace QmlJsDebugClient

View File

@@ -159,6 +159,12 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
int event;
stream >> event;
// stop with the first data
if (d->recording && event != StartTrace)
setRecordingFromServer(false);
else if ((!d->recording) && event == StartTrace)
setRecordingFromServer(true);
if (event == EndTrace) {
emit this->traceFinished(time);
d->maximumTime = time;
@@ -169,9 +175,6 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
emit this->frame(time, frameRate, animationCount);
d->maximumTime = qMax(time, d->maximumTime);
} else if (event == StartTrace) {
// special: StartTrace is now asynchronous
if (!d->recording)
setRecordingFromServer(true);
emit this->traceStarted(time);
d->maximumTime = time;
} else if (event < MaximumEventType) {
@@ -191,6 +194,9 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
d->rangeStartTimes[range].push(time);
d->inProgressRanges |= (static_cast<qint64>(1) << range);
++d->rangeCount[range];
// stop with the first data
if (d->recording)
setRecordingFromServer(false);
} else if (messageType == RangeData) {
QString data;
stream >> data;

View File

@@ -80,10 +80,9 @@ public:
bool isEnabled() const;
bool isRecording() const;
void setRecording(bool);
public slots:
void setRecording(bool);
void setRecordingFromServer(bool);
void clearData();
void sendRecordingStatus();
@@ -106,6 +105,9 @@ protected:
virtual void statusChanged(Status);
virtual void messageReceived(const QByteArray &);
private:
void setRecordingFromServer(bool);
private:
class QmlProfilerTraceClientPrivate *d;
};

View File

@@ -118,6 +118,16 @@ void QV8ProfilerClient::setRecording(bool v)
emit recordingChanged(v);
}
void QV8ProfilerClient::setRecordingFromServer(bool v)
{
if (v == d->recording)
return;
d->recording = v;
emit recordingChanged(v);
}
void QV8ProfilerClient::statusChanged(Status /*status*/)
{
emit enabledChanged();
@@ -133,7 +143,10 @@ void QV8ProfilerClient::messageReceived(const QByteArray &data)
stream >> messageType;
if (messageType == V8Complete) {
setRecordingFromServer(false);
emit complete();
} else if (messageType == V8ProfilingStarted) {
setRecordingFromServer(true);
} else if (messageType == V8Entry) {
QString filename;
QString function;

View File

@@ -52,6 +52,9 @@ public:
enum Message {
V8Entry,
V8Complete,
V8SnapshotChunk,
V8SnapshotComplete,
V8ProfilingStarted,
V8MaximumMessage
};
@@ -61,9 +64,9 @@ public:
bool isEnabled() const;
bool isRecording() const;
void setRecording(bool);
public slots:
void setRecording(bool);
void clearData();
void sendRecordingStatus();
@@ -77,6 +80,9 @@ signals:
void enabledChanged();
void cleared();
private:
void setRecordingFromServer(bool);
protected:
virtual void statusChanged(Status);
virtual void messageReceived(const QByteArray &);

View File

@@ -60,17 +60,19 @@ Item {
function updateHeight() {
height = root.singleRowHeight * (1 +
(expanded ? qmlEventList.uniqueEventsOfType(typeIndex) : qmlEventList.maxNestingForType(typeIndex)));
(expanded ? qmlProfilerDataModel.uniqueEventsOfType(typeIndex) :
qmlProfilerDataModel.maxNestingForType(typeIndex)));
}
function getDescriptions() {
var desc=[];
var ids=[];
var extdesc=[];
for (var i=0; i<qmlEventList.uniqueEventsOfType(typeIndex); i++) {
desc[i] = qmlEventList.eventTextForType(typeIndex, i);
ids[i] = qmlEventList.eventIdForType(typeIndex, i);
extdesc[i] = qmlEventList.eventDisplayNameForType(typeIndex, i) + " : " + desc[i];
for (var i=0; i<qmlProfilerDataModel.uniqueEventsOfType(typeIndex); i++) {
desc[i] = qmlProfilerDataModel.eventTextForType(typeIndex, i);
ids[i] = qmlProfilerDataModel.eventIdForType(typeIndex, i);
extdesc[i] = qmlProfilerDataModel.eventDisplayNameForType(typeIndex, i) +
" : " + desc[i];
}
descriptions = desc;
eventIds = ids;
@@ -79,18 +81,18 @@ Item {
}
Connections {
target: qmlEventList
target: qmlProfilerDataModel
onReloadDetailLabels: getDescriptions();
onStateChanged: {
// Empty
if (qmlEventList.getCurrentStateFromQml() == 0) {
if (qmlProfilerDataModel.getCurrentStateFromQml() == 0) {
descriptions = [];
eventIds = [];
extdescriptions = [];
updateHeight();
} else
// Done
if (qmlEventList.getCurrentStateFromQml() == 3) {
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
getDescriptions();
}
}

View File

@@ -51,11 +51,16 @@ Rectangle {
property alias selectionLocked : view.selectionLocked
signal updateLockButton
property alias selectedItem: view.selectedItem
signal selectedEventIdChanged(int eventId)
signal selectedEventChanged(int eventId)
property bool lockItemSelection : false
property variant names: [ qsTr("Painting"), qsTr("Compiling"), qsTr("Creating"), qsTr("Binding"), qsTr("Handling Signal")]
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC", "#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
property variant names: [ qsTr("Painting"),
qsTr("Compiling"),
qsTr("Creating"),
qsTr("Binding"),
qsTr("Handling Signal")]
property variant colors : [ "#99CCB3", "#99CCCC", "#99B3CC",
"#9999CC", "#CC99B3", "#CC99CC", "#CCCC99", "#CCB399" ]
property variant mainviewTimePerPixel : 0
@@ -64,9 +69,6 @@ Rectangle {
property int lineNumber: -1
property int columnNumber: 0
property real elapsedTime
signal updateTimer
signal updateRangeButton
property bool selectionRangeMode: false
@@ -77,7 +79,11 @@ Rectangle {
signal changeToolTip(string text)
signal updateVerticalScroll(int newPosition)
property bool applicationDied : false
property bool recordingEnabled: false
property bool appKilled : false
property date recordingStartDate
property real elapsedTime
// ***** connections with external objects
Connections {
@@ -92,7 +98,8 @@ Rectangle {
backgroundMarks.updateMarks(startTime, endTime);
view.updateFlickRange(startTime, endTime);
if (duration > 0) {
var candidateWidth = qmlEventList.traceDuration() * flick.width / duration;
var candidateWidth = qmlProfilerDataModel.traceDuration() *
flick.width / duration;
if (flick.contentWidth !== candidateWidth)
flick.contentWidth = candidateWidth;
}
@@ -101,20 +108,21 @@ Rectangle {
}
Connections {
target: qmlEventList
target: qmlProfilerDataModel
onCountChanged: {
eventCount = qmlEventList.count();
eventCount = qmlProfilerDataModel.count();
if (eventCount === 0)
root.clearAll();
if (eventCount > 1) {
root.progress = Math.min(1.0,
(qmlEventList.lastTimeMark() - qmlEventList.traceStartTime()) / root.elapsedTime * 1e-9 );
(qmlProfilerDataModel.lastTimeMark() -
qmlProfilerDataModel.traceStartTime()) / root.elapsedTime * 1e-9 );
} else {
root.progress = 0;
}
}
onStateChanged: {
switch (qmlEventList.getCurrentStateFromQml()) {
switch (qmlProfilerDataModel.getCurrentStateFromQml()) {
case 0: {
root.clearAll();
break;
@@ -133,7 +141,9 @@ Rectangle {
dataAvailable = true;
view.visible = true;
view.requestPaint();
zoomControl.setRange(qmlEventList.traceStartTime(), qmlEventList.traceStartTime() + qmlEventList.traceDuration()/10);
zoomControl.setRange(qmlProfilerDataModel.traceStartTime(),
qmlProfilerDataModel.traceStartTime() +
qmlProfilerDataModel.traceDuration()/10);
break;
}
}
@@ -151,7 +161,7 @@ Rectangle {
function clearData() {
view.clearData();
dataAvailable = false;
applicationDied = false;
appKilled = false;
eventCount = 0;
hideRangeDetails();
selectionRangeMode = false;
@@ -166,8 +176,6 @@ Rectangle {
function clearAll() {
clearDisplay();
root.elapsedTime = 0;
root.updateTimer();
}
function nextEvent() {
@@ -180,9 +188,10 @@ Rectangle {
function updateWindowLength(absoluteFactor) {
var windowLength = view.endTime - view.startTime;
if (qmlEventList.traceEndTime() <= qmlEventList.traceStartTime() || windowLength <= 0)
if (qmlProfilerDataModel.traceEndTime() <= qmlProfilerDataModel.traceStartTime() ||
windowLength <= 0)
return;
var currentFactor = windowLength / qmlEventList.traceDuration();
var currentFactor = windowLength / qmlProfilerDataModel.traceDuration();
updateZoom(absoluteFactor / currentFactor);
}
@@ -193,8 +202,8 @@ Rectangle {
windowLength = min_length;
var newWindowLength = windowLength * relativeFactor;
if (newWindowLength > qmlEventList.traceDuration()) {
newWindowLength = qmlEventList.traceDuration();
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
newWindowLength = qmlProfilerDataModel.traceDuration();
relativeFactor = newWindowLength / windowLength;
}
if (newWindowLength < min_length) {
@@ -205,7 +214,7 @@ Rectangle {
var fixedPoint = (view.startTime + view.endTime) / 2;
if (view.selectedItem !== -1) {
// center on selected item if it's inside the current screen
var newFixedPoint = qmlEventList.getStartTime(view.selectedItem);
var newFixedPoint = qmlProfilerDataModel.getStartTime(view.selectedItem);
if (newFixedPoint >= view.startTime && newFixedPoint < view.endTime)
fixedPoint = newFixedPoint;
}
@@ -222,8 +231,8 @@ Rectangle {
windowLength = min_length;
var newWindowLength = windowLength * relativeFactor;
if (newWindowLength > qmlEventList.traceDuration()) {
newWindowLength = qmlEventList.traceDuration();
if (newWindowLength > qmlProfilerDataModel.traceDuration()) {
newWindowLength = qmlProfilerDataModel.traceDuration();
relativeFactor = newWindowLength / windowLength;
}
if (newWindowLength < min_length) {
@@ -241,8 +250,8 @@ Rectangle {
var newStart = Math.floor(centerPoint - windowLength/2);
if (newStart < 0)
newStart = 0;
if (newStart + windowLength > qmlEventList.traceEndTime())
newStart = qmlEventList.traceEndTime() - windowLength;
if (newStart + windowLength > qmlProfilerDataModel.traceEndTime())
newStart = qmlProfilerDataModel.traceEndTime() - windowLength;
zoomControl.setRange(newStart, newStart + windowLength);
}
@@ -252,17 +261,16 @@ Rectangle {
return;
// if item is outside of the view, jump back to its position
if (qmlEventList.getEndTime(itemIndex) < view.startTime || qmlEventList.getStartTime(itemIndex) > view.endTime) {
recenter((qmlEventList.getStartTime(itemIndex) + qmlEventList.getEndTime(itemIndex)) / 2);
if (qmlProfilerDataModel.getEndTime(itemIndex) < view.startTime ||
qmlProfilerDataModel.getStartTime(itemIndex) > view.endTime) {
recenter((qmlProfilerDataModel.getStartTime(itemIndex) +
qmlProfilerDataModel.getEndTime(itemIndex)) / 2);
}
}
function globalZoom() {
zoomControl.setRange(qmlEventList.traceStartTime(), qmlEventList.traceEndTime());
}
function wheelZoom(wheelCenter, wheelDelta) {
if (qmlEventList.traceEndTime() > qmlEventList.traceStartTime() && wheelDelta !== 0) {
if (qmlProfilerDataModel.traceEndTime() > qmlProfilerDataModel.traceStartTime() &&
wheelDelta !== 0) {
if (wheelDelta>0)
updateZoomCentered(wheelCenter, 1/1.2);
else
@@ -311,34 +319,22 @@ Rectangle {
onSelectedItemChanged: {
if (selectedItem != -1 && !lockItemSelection) {
lockItemSelection = true;
selectedEventIdChanged( qmlEventList.getEventId(selectedItem) );
selectedEventChanged( qmlProfilerDataModel.getEventId(selectedItem) );
lockItemSelection = false;
}
}
// ***** child items
Timer {
id: elapsedTimer
property date startDate
property bool reset: true
running: connection.recording && connection.enabled
repeat: true
onRunningChanged: {
if (running) reset = true;
}
interval: 100
triggeredOnStart: true
onTriggered: {
if (reset) {
startDate = new Date();
reset = false;
}
var time = (new Date() - startDate)/1000;
root.elapsedTime = time.toFixed(1);
root.updateTimer();
onRecordingEnabledChanged: {
if (recordingEnabled) {
recordingStartDate = new Date();
elapsedTime = 0;
} else {
elapsedTime = (new Date() - recordingStartDate)/1000.0;
}
}
// ***** child items
TimeMarks {
id: backgroundMarks
y: labels.y
@@ -380,7 +376,8 @@ Rectangle {
selectionRange.isDragging = false;
}
onDoubleClicked: {
zoomControl.setRange(selectionRange.startTime, selectionRange.startTime + selectionRange.duration);
zoomControl.setRange(selectionRange.startTime,
selectionRange.startTime + selectionRange.duration);
root.selectionRangeMode = false;
root.updateRangeButton();
}
@@ -394,10 +391,10 @@ Rectangle {
z: 2
}
TimelineView {
TimelineRenderer {
id: view
eventList: qmlEventList
profilerDataModel: qmlProfilerDataModel
x: flick.contentX
width: flick.width
@@ -405,9 +402,13 @@ Rectangle {
property variant startX: 0
onStartXChanged: {
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) + qmlEventList.traceStartTime();
var newStartTime = Math.round(startX * (endTime - startTime) / flick.width) +
qmlProfilerDataModel.traceStartTime();
if (Math.abs(newStartTime - startTime) > 1) {
var newEndTime = Math.round((startX+flick.width)* (endTime - startTime) / flick.width) + qmlEventList.traceStartTime();
var newEndTime = Math.round((startX+flick.width) *
(endTime - startTime) /
flick.width) +
qmlProfilerDataModel.traceStartTime();
zoomControl.setRange(newStartTime, newEndTime);
}
@@ -419,7 +420,8 @@ Rectangle {
if (start !== startTime || end !== endTime) {
startTime = start;
endTime = end;
var newStartX = (startTime - qmlEventList.traceStartTime()) * flick.width / (endTime-startTime);
var newStartX = (startTime - qmlProfilerDataModel.traceStartTime()) *
flick.width / (endTime-startTime);
if (Math.abs(newStartX - startX) >= 1)
startX = newStartX;
}
@@ -428,24 +430,25 @@ Rectangle {
onSelectedItemChanged: {
if (selectedItem !== -1) {
// display details
rangeDetails.duration = qmlEventList.getDuration(selectedItem)/1000.0;
rangeDetails.label = qmlEventList.getDetails(selectedItem);
rangeDetails.file = qmlEventList.getFilename(selectedItem);
rangeDetails.line = qmlEventList.getLine(selectedItem);
rangeDetails.column = qmlEventList.getColumn(selectedItem);
rangeDetails.type = root.names[qmlEventList.getType(selectedItem)];
rangeDetails.isBindingLoop = qmlEventList.getBindingLoopDest(selectedItem)!==-1;
rangeDetails.duration = qmlProfilerDataModel.getDuration(selectedItem)/1000.0;
rangeDetails.label = qmlProfilerDataModel.getDetails(selectedItem);
rangeDetails.file = qmlProfilerDataModel.getFilename(selectedItem);
rangeDetails.line = qmlProfilerDataModel.getLine(selectedItem);
rangeDetails.column = qmlProfilerDataModel.getColumn(selectedItem);
rangeDetails.type = root.names[qmlProfilerDataModel.getType(selectedItem)];
rangeDetails.isBindingLoop = qmlProfilerDataModel.getBindingLoopDest(selectedItem)!==-1;
rangeDetails.visible = true;
// center view (horizontally)
var windowLength = view.endTime - view.startTime;
var eventStartTime = qmlEventList.getStartTime(selectedItem);
var eventEndTime = eventStartTime + qmlEventList.getDuration(selectedItem);
var eventStartTime = qmlProfilerDataModel.getStartTime(selectedItem);
var eventEndTime = eventStartTime +
qmlProfilerDataModel.getDuration(selectedItem);
if (eventEndTime < view.startTime || eventStartTime > view.endTime) {
var center = (eventStartTime + eventEndTime)/2;
var from = Math.min(qmlEventList.traceEndTime()-windowLength,
var from = Math.min(qmlProfilerDataModel.traceEndTime()-windowLength,
Math.max(0, Math.floor(center - windowLength/2)));
zoomControl.setRange(from, from + windowLength);
@@ -456,8 +459,10 @@ Rectangle {
if (itemY < root.scrollY) {
root.updateVerticalScroll(itemY);
} else
if (itemY + root.singleRowHeight > root.scrollY + root.candidateHeight) {
root.updateVerticalScroll(itemY + root.singleRowHeight - root.candidateHeight);
if (itemY + root.singleRowHeight >
root.scrollY + root.candidateHeight) {
root.updateVerticalScroll(itemY + root.singleRowHeight -
root.candidateHeight);
}
} else {
root.hideRangeDetails();
@@ -466,14 +471,18 @@ Rectangle {
onItemPressed: {
if (pressedItem !== -1) {
root.gotoSourceLocation(qmlEventList.getFilename(pressedItem), qmlEventList.getLine(pressedItem), qmlEventList.getColumn(pressedItem));
root.gotoSourceLocation(qmlProfilerDataModel.getFilename(pressedItem),
qmlProfilerDataModel.getLine(pressedItem),
qmlProfilerDataModel.getColumn(pressedItem));
}
}
// hack to pass mouse events to the other mousearea if enabled
startDragArea: selectionRangeDrag.enabled ? selectionRangeDrag.x : -flick.contentX
startDragArea: selectionRangeDrag.enabled ? selectionRangeDrag.x :
-flick.contentX
endDragArea: selectionRangeDrag.enabled ?
selectionRangeDrag.x + selectionRangeDrag.width : -flick.contentX-1
selectionRangeDrag.x + selectionRangeDrag.width :
-flick.contentX-1
}
MouseArea {
id: selectionRangeControl

View File

@@ -32,7 +32,7 @@
.pragma library
var qmlEventList = 0;
var qmlProfilerDataModel = 0;
//draw background of the graph
function drawGraph(canvas, ctxt, region)
@@ -44,7 +44,7 @@ function drawGraph(canvas, ctxt, region)
//draw the actual data to be graphed
function drawData(canvas, ctxt, region)
{
if ((!qmlEventList) || qmlEventList.count() == 0)
if ((!qmlProfilerDataModel) || qmlProfilerDataModel.count() == 0)
return;
var typeCount = 5;
@@ -53,17 +53,18 @@ function drawData(canvas, ctxt, region)
var height = canvas.height - bump;
var blockHeight = height / typeCount;
var spacing = width / qmlEventList.traceDuration();
var spacing = width / qmlProfilerDataModel.traceDuration();
var highest = [0,0,0,0,0]; // note: change if typeCount changes
for (var ii = 0; ii < qmlEventList.count(); ++ii) {
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
var xx = (qmlEventList.getStartTime(ii) - qmlEventList.traceStartTime()) * spacing;
var xx = (qmlProfilerDataModel.getStartTime(ii) -
qmlProfilerDataModel.traceStartTime()) * spacing;
if (xx > region.x + region.width)
continue;
var eventWidth = qmlEventList.getDuration(ii) * spacing;
var eventWidth = qmlProfilerDataModel.getDuration(ii) * spacing;
if (xx + eventWidth < region.x)
continue;
@@ -71,24 +72,26 @@ function drawData(canvas, ctxt, region)
eventWidth = 1;
xx = Math.round(xx);
var ty = qmlEventList.getType(ii);
var ty = qmlProfilerDataModel.getType(ii);
if (xx + eventWidth > highest[ty]) {
// special: animations
if (ty === 0 && qmlEventList.getAnimationCount(ii) >= 0) {
var vertScale = qmlEventList.getMaximumAnimationCount() - qmlEventList.getMinimumAnimationCount();
if (ty === 0 && qmlProfilerDataModel.getAnimationCount(ii) >= 0) {
var vertScale = qmlProfilerDataModel.getMaximumAnimationCount() -
qmlProfilerDataModel.getMinimumAnimationCount();
if (vertScale < 1)
vertScale = 1;
var fraction = (qmlEventList.getAnimationCount(ii) - qmlEventList.getMinimumAnimationCount()) / vertScale;
var fraction = (qmlProfilerDataModel.getAnimationCount(ii) -
qmlProfilerDataModel.getMinimumAnimationCount()) / vertScale;
var eventHeight = blockHeight * (fraction * 0.85 + 0.15);
var yy = bump + ty*blockHeight + blockHeight - eventHeight;
var fpsFraction = qmlEventList.getFramerate(ii) / 60.0;
var fpsFraction = qmlProfilerDataModel.getFramerate(ii) / 60.0;
if (fpsFraction > 1.0)
fpsFraction = 1.0;
ctxt.fillStyle = "hsl("+(fpsFraction*0.27+0.028)+",0.3,0.65)";
ctxt.fillRect(xx, yy, eventWidth, eventHeight);
} else {
var hue = ( qmlEventList.getEventId(ii) * 25 ) % 360;
var hue = ( qmlProfilerDataModel.getEventId(ii) * 25 ) % 360;
ctxt.fillStyle = "hsl("+(hue/360.0+0.001)+",0.3,0.65)";
ctxt.fillRect(xx, bump + ty*blockHeight, eventWidth, blockHeight);
}
@@ -100,12 +103,13 @@ function drawData(canvas, ctxt, region)
ctxt.strokeStyle = "orange";
ctxt.lineWidth = 2;
var radius = 1;
for (var ii = 0; ii < qmlEventList.count(); ++ii) {
if (qmlEventList.getBindingLoopDest(ii) >= 0) {
var xcenter = Math.round(qmlEventList.getStartTime(ii) +
qmlEventList.getDuration(ii) -
qmlEventList.traceStartTime()) * spacing;
var ycenter = Math.round(bump + qmlEventList.getType(ii) * blockHeight + blockHeight/2);
for (var ii = 0; ii < qmlProfilerDataModel.count(); ++ii) {
if (qmlProfilerDataModel.getBindingLoopDest(ii) >= 0) {
var xcenter = Math.round(qmlProfilerDataModel.getStartTime(ii) +
qmlProfilerDataModel.getDuration(ii) -
qmlProfilerDataModel.traceStartTime()) * spacing;
var ycenter = Math.round(bump + qmlProfilerDataModel.getType(ii) *
blockHeight + blockHeight/2);
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
ctxt.stroke();
}
@@ -114,19 +118,20 @@ function drawData(canvas, ctxt, region)
function drawTimeBar(canvas, ctxt, region)
{
if (!qmlEventList)
if (!qmlProfilerDataModel)
return;
var width = canvas.width;
var height = 10;
var startTime = qmlEventList.traceStartTime();
var endTime = qmlEventList.traceEndTime();
var startTime = qmlProfilerDataModel.traceStartTime();
var endTime = qmlProfilerDataModel.traceEndTime();
var totalTime = qmlEventList.traceDuration();
var totalTime = qmlProfilerDataModel.traceDuration();
var spacing = width / totalTime;
var initialBlockLength = 120;
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width * initialBlockLength ) / Math.LN2 ) );
var timePerBlock = Math.pow(2, Math.floor( Math.log( totalTime / width *
initialBlockLength ) / Math.LN2 ) );
var pixelsPerBlock = timePerBlock * spacing;
var pixelsPerSection = pixelsPerBlock / 5;
var blockCount = width / pixelsPerBlock;

View File

@@ -51,8 +51,8 @@ Canvas2D {
}
function updateRange() {
var newStartTime = Math.round(rangeMover.x * qmlEventList.traceDuration() / width) + qmlEventList.traceStartTime();
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlEventList.traceDuration() / width) + qmlEventList.traceStartTime();
var newStartTime = Math.round(rangeMover.x * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerDataModel.traceDuration() / width) + qmlProfilerDataModel.traceStartTime();
if (startTime !== newStartTime || endTime !== newEndTime) {
zoomControl.setRange(newStartTime, newEndTime);
}
@@ -62,13 +62,13 @@ Canvas2D {
Connections {
target: zoomControl
onRangeChanged: {
if (qmlEventList) {
if (qmlProfilerDataModel) {
startTime = zoomControl.startTime();
endTime = zoomControl.endTime();
var newRangeX = (startTime - qmlEventList.traceStartTime()) * width / qmlEventList.traceDuration();
var newRangeX = (startTime - qmlProfilerDataModel.traceStartTime()) * width / qmlProfilerDataModel.traceDuration();
if (rangeMover.x !== newRangeX)
rangeMover.x = newRangeX;
var newWidth = (endTime-startTime) * width / qmlEventList.traceDuration();
var newWidth = (endTime-startTime) * width / qmlProfilerDataModel.traceDuration();
if (rangeMover.width !== newWidth)
rangeMover.width = newWidth;
}
@@ -76,10 +76,10 @@ Canvas2D {
}
Connections {
target: qmlEventList
target: qmlProfilerDataModel
onStateChanged: {
// State is "done"
if (qmlEventList.getCurrentStateFromQml() == 3) {
if (qmlProfilerDataModel.getCurrentStateFromQml() == 3) {
dataAvailable = true;
requestRedraw();
}
@@ -88,7 +88,7 @@ Canvas2D {
// ***** slots
onDrawRegion: {
Plotter.qmlEventList = qmlEventList;
Plotter.qmlProfilerDataModel = qmlProfilerDataModel;
if (dataAvailable) {
Plotter.plot(canvas, ctxt, region);
} else {

View File

@@ -50,7 +50,7 @@ Rectangle {
property string endTimeString: detailedPrintTime(startTime+duration)
property string durationString: detailedPrintTime(duration)
property variant startTime: x * selectionRange.viewTimePerPixel + qmlEventList.traceStartTime()
property variant startTime: x * selectionRange.viewTimePerPixel + qmlProfilerDataModel.traceStartTime()
property variant duration: width * selectionRange.viewTimePerPixel
property variant viewTimePerPixel: 1
property variant creationState : 0

View File

@@ -69,7 +69,7 @@ Item {
states: [
// no data available
State {
when: (root.eventCount == 0) && !elapsedTimer.running
when: (root.eventCount == 0) && !root.recordingEnabled
PropertyChanges {
target: statusDisplay
visible: true
@@ -85,7 +85,7 @@ Item {
},
// running app
State {
when: elapsedTimer.running
when: root.recordingEnabled
PropertyChanges {
target: statusDisplay
visible: true
@@ -99,7 +99,7 @@ Item {
// loading data
State {
name: "loading"
when: (!root.dataAvailable) && (root.eventCount > 0) && !root.applicationDied
when: !root.dataAvailable && (root.eventCount > 0) && !root.appKilled
PropertyChanges {
target: statusDisplay
visible: true
@@ -118,7 +118,7 @@ Item {
// application died
State {
name: "deadApp"
when: (!root.dataAvailable) && (root.eventCount > 0) && root.applicationDied
when: !root.dataAvailable && (root.eventCount > 0) && root.appKilled
PropertyChanges {
target: statusDisplay
visible: true

View File

@@ -91,15 +91,15 @@ Canvas2D {
// gray off out-of-bounds areas
var rectWidth;
if (startTime < qmlEventList.traceStartTime()) {
if (startTime < qmlProfilerDataModel.traceStartTime()) {
ctxt.fillStyle = "rgba(127,127,127,0.2)";
rectWidth = (qmlEventList.traceStartTime() - startTime) * spacing;
rectWidth = (qmlProfilerDataModel.traceStartTime() - startTime) * spacing;
ctxt.fillRect(0, 0, rectWidth, height);
}
if (endTime > qmlEventList.traceEndTime()) {
if (endTime > qmlProfilerDataModel.traceEndTime()) {
ctxt.fillStyle = "rgba(127,127,127,0.2)";
var rectX = (qmlEventList.traceEndTime() - startTime) * spacing;
rectWidth = (endTime - qmlEventList.traceEndTime()) * spacing;
var rectX = (qmlProfilerDataModel.traceEndTime() - startTime) * spacing;
rectWidth = (endTime - qmlProfilerDataModel.traceEndTime()) * spacing;
ctxt.fillRect(rectX, 0, rectWidth, height);
}
}
@@ -126,8 +126,8 @@ Canvas2D {
var cumulatedHeight = 0;
for (var i=0; i<labels.rowCount; i++) {
cumulatedHeight += root.singleRowHeight + (labels.rowExpanded[i] ?
qmlEventList.uniqueEventsOfType(i) * root.singleRowHeight :
qmlEventList.maxNestingForType(i) * root.singleRowHeight);
qmlProfilerDataModel.uniqueEventsOfType(i) * root.singleRowHeight :
qmlProfilerDataModel.maxNestingForType(i) * root.singleRowHeight);
ctxt.strokeStyle = "#B0B0B0";
ctxt.beginPath();

View File

@@ -24,14 +24,19 @@ SOURCES += \
qmlprofilerplugin.cpp \
qmlprofilertool.cpp \
qmlprofilerengine.cpp \
tracewindow.cpp \
timelineview.cpp \
qmlprofilerattachdialog.cpp \
localqmlprofilerrunner.cpp \
codaqmlprofilerrunner.cpp \
remotelinuxqmlprofilerrunner.cpp \
qmlprofilereventview.cpp \
qmlprofilerdetailsrewriter.cpp
qmlprofilerdetailsrewriter.cpp \
qmlprofilertraceview.cpp \
timelinerenderer.cpp \
qmlprofilerstatemanager.cpp \
qv8profilerdatamodel.cpp \
qmlprofilerdatamodel.cpp \
qmlprofilerclientmanager.cpp \
qmlprofilerviewmanager.cpp
HEADERS += \
qmlprofilerconstants.h \
@@ -39,22 +44,26 @@ HEADERS += \
qmlprofilerplugin.h \
qmlprofilertool.h \
qmlprofilerengine.h \
tracewindow.h \
timelineview.h \
qmlprofilerattachdialog.h \
abstractqmlprofilerrunner.h \
localqmlprofilerrunner.h \
codaqmlprofilerrunner.h \
remotelinuxqmlprofilerrunner.h \
qmlprofilereventview.h \
qmlprofilerdetailsrewriter.h
qmlprofilerdetailsrewriter.h \
qmlprofilertraceview.h \
timelinerenderer.h \
qmlprofilerstatemanager.h \
qv8profilerdatamodel.h \
qmlprofilerdatamodel.h \
qmlprofilerclientmanager.h \
qmlprofilerviewmanager.h
RESOURCES += \
qml/qmlprofiler.qrc
OTHER_FILES += \
qml/Detail.qml \
qml/Elapsed.qml \
qml/Label.qml \
qml/MainView.qml \
qml/RangeDetails.qml \
@@ -64,8 +73,7 @@ OTHER_FILES += \
qml/StatusDisplay.qml \
qml/SelectionRange.qml \
qml/SelectionRangeDetails.qml \
qml/Overview.qml \
qml/Overview.js
qml/Overview.qml
FORMS += \
qmlprofilerattachdialog.ui

View File

@@ -35,27 +35,37 @@ QtcPlugin {
"codaqmlprofilerrunner.h",
"localqmlprofilerrunner.cpp",
"localqmlprofilerrunner.h",
"qmlprofiler_global.h",
"qmlprofilerattachdialog.cpp",
"qmlprofilerattachdialog.h",
"qmlprofilerattachdialog.ui",
"qmlprofilerclientmanager.cpp",
"qmlprofilerclientmanager.h",
"qmlprofilerconstants.h",
"qmlprofilerdatamodel.cpp",
"qmlprofilerdatamodel.h",
"qmlprofilerdetailsrewriter.cpp",
"qmlprofilerdetailsrewriter.h",
"qmlprofilerengine.cpp",
"qmlprofilerengine.h",
"qmlprofilereventview.cpp",
"qmlprofilereventview.h",
"qmlprofiler_global.h",
"qmlprofilerplugin.cpp",
"qmlprofilerplugin.h",
"qmlprofilerstatemanager.cpp",
"qmlprofilerstatemanager.h",
"qmlprofilertool.cpp",
"qmlprofilertool.h",
"qmlprofilertraceview.cpp",
"qmlprofilertraceview.h",
"qmlprofilerviewmanager.cpp",
"qmlprofilerviewmanager.h",
"qv8profilerdatamodel.cpp",
"qv8profilerdatamodel.h",
"remotelinuxqmlprofilerrunner.cpp",
"remotelinuxqmlprofilerrunner.h",
"timelineview.cpp",
"timelineview.h",
"tracewindow.cpp",
"tracewindow.h",
"timelinerenderer.cpp",
"timelinerenderer.h",
"canvas/qdeclarativecanvas.cpp",
"canvas/qdeclarativecanvas_p.h",
"canvas/qdeclarativecanvastimer.cpp",
@@ -75,7 +85,8 @@ QtcPlugin {
"qml/StatusDisplay.qml",
"qml/TimeDisplay.qml",
"qml/TimeMarks.qml",
"qml/qmlprofiler.qrc"
"qml/qmlprofiler.qrc",
"qml/Overview.js"
]
}

View File

@@ -0,0 +1,426 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmlprofilerclientmanager.h"
#include "qmlprofilertool.h"
#include "qmlprofilerplugin.h"
#include <qmljsdebugclient/qdeclarativedebugclient.h>
#include <qmljsdebugclient/qmlprofilertraceclient.h>
#include <qmljsdebugclient/qv8profilerclient.h>
#include <utils/qtcassert.h>
#include <QWeakPointer>
#include <QTimer>
#include <QMessageBox>
using namespace QmlJsDebugClient;
using namespace Core;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerClientManager::QmlProfilerClientManagerPrivate {
public:
QmlProfilerClientManagerPrivate(QmlProfilerClientManager *qq) { Q_UNUSED(qq); }
QmlProfilerStateManager* profilerState;
QDeclarativeDebugConnection *connection;
QWeakPointer<QmlProfilerTraceClient> qmlclientplugin;
QWeakPointer<QV8ProfilerClient> v8clientplugin;
QTimer connectionTimer;
int connectionAttempts;
enum ConnectMode {
TcpConnection, OstConnection
};
ConnectMode connectMode;
QString tcpHost;
quint64 tcpPort;
QString ostDevice;
QString sysroot;
bool v8DataReady;
bool qmlDataReady;
};
QmlProfilerClientManager::QmlProfilerClientManager(QObject *parent) :
QObject(parent), d(new QmlProfilerClientManagerPrivate(this))
{
setObjectName("QML Profiler Connections");
d->profilerState = 0;
d->connection = 0;
d->connectionAttempts = 0;
d->v8DataReady = false;
d->qmlDataReady = false;
d->connectionTimer.setInterval(200);
connect(&d->connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
}
QmlProfilerClientManager::~QmlProfilerClientManager()
{
disconnectClientSignals();
delete d->connection;
delete d->qmlclientplugin.data();
delete d->v8clientplugin.data();
delete d;
}
////////////////////////////////////////////////////////////////
// Interface
void QmlProfilerClientManager::setTcpConnection(QString host, quint64 port)
{
d->connectMode = QmlProfilerClientManagerPrivate::TcpConnection;
d->tcpHost = host;
d->tcpPort = port;
}
void QmlProfilerClientManager::setOstConnection(QString ostDevice)
{
d->connectMode = QmlProfilerClientManagerPrivate::OstConnection;
d->ostDevice = ostDevice;
}
void QmlProfilerClientManager::clearBufferedData()
{
if (d->qmlclientplugin)
d->qmlclientplugin.data()->clearData();
if (d->v8clientplugin)
d->v8clientplugin.data()->clearData();
}
////////////////////////////////////////////////////////////////
// Internal
void QmlProfilerClientManager::connectClient(quint16 port)
{
if (d->connection)
delete d->connection;
d->connection = new QDeclarativeDebugConnection;
enableServices();
connect(d->connection, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(connectionStateChanged()));
d->connectionTimer.start();
d->tcpPort = port;
}
void QmlProfilerClientManager::enableServices()
{
QTC_ASSERT(d->profilerState, return);
disconnectClientSignals();
d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
delete d->qmlclientplugin.data();
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection);
delete d->v8clientplugin.data();
d->v8clientplugin = new QV8ProfilerClient(d->connection);
connectClientSignals();
}
void QmlProfilerClientManager::connectClientSignals()
{
QTC_ASSERT(d->profilerState, return);
if (d->qmlclientplugin) {
connect(d->qmlclientplugin.data(), SIGNAL(complete()),
this, SLOT(qmlComplete()));
connect(d->qmlclientplugin.data(),
SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
this,
SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
connect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
this, SIGNAL(traceFinished(qint64)));
connect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
this, SIGNAL(traceStarted(qint64)));
connect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
this, SIGNAL(addFrameEvent(qint64,int,int)));
connect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
// fixme: this should be unified for both clients
connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
}
if (d->v8clientplugin) {
connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
connect(d->v8clientplugin.data(),
SIGNAL(v8range(int,QString,QString,int,double,double)),
this,
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
connect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
}
}
void QmlProfilerClientManager::disconnectClientSignals()
{
if (d->qmlclientplugin) {
disconnect(d->qmlclientplugin.data(), SIGNAL(complete()),
this, SLOT(qmlComplete()));
disconnect(d->qmlclientplugin.data(),
SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
this,
SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
disconnect(d->qmlclientplugin.data(), SIGNAL(traceFinished(qint64)),
this, SIGNAL(traceFinished(qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(traceStarted(qint64)),
this, SIGNAL(traceStarted(qint64)));
disconnect(d->qmlclientplugin.data(), SIGNAL(frame(qint64,int,int)),
this, SIGNAL(addFrameEvent(qint64,int,int)));
disconnect(d->qmlclientplugin.data(), SIGNAL(enabledChanged()),
d->qmlclientplugin.data(), SLOT(sendRecordingStatus()));
// fixme: this should be unified for both clients
disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
}
if (d->v8clientplugin) {
disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
disconnect(d->v8clientplugin.data(),
SIGNAL(v8range(int,QString,QString,int,double,double)),
this,
SIGNAL(addV8Event(int,QString,QString,int,double,double)));
disconnect(d->v8clientplugin.data(), SIGNAL(enabledChanged()),
d->v8clientplugin.data(), SLOT(sendRecordingStatus()));
}
}
void QmlProfilerClientManager::connectToClient()
{
if (!d->connection || d->connection->state() != QAbstractSocket::UnconnectedState)
return;
if (d->connectMode == QmlProfilerClientManagerPrivate::TcpConnection) {
QmlProfilerTool::logStatus(QString("QML Profiler: Connecting to %1:%2 ...").arg(d->tcpHost, QString::number(d->tcpPort)));
d->connection->connectToHost(d->tcpHost, d->tcpPort);
} else {
QmlProfilerTool::logStatus(QString("QML Profiler: Connecting to %1 ...").arg(d->tcpHost));
d->connection->connectToOst(d->ostDevice);
}
}
void QmlProfilerClientManager::disconnectClient()
{
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
// method to complete before deleting object
if (d->connection) {
d->connection->deleteLater();
d->connection = 0;
}
}
void QmlProfilerClientManager::tryToConnect()
{
++d->connectionAttempts;
if (d->connection && d->connection->isConnected()) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
} else if (d->connectionAttempts == 50) {
d->connectionTimer.stop();
d->connectionAttempts = 0;
QMessageBox *infoBox = QmlProfilerTool::requestMessageBox();
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
"Do you want to retry?"));
infoBox->setStandardButtons(QMessageBox::Retry |
QMessageBox::Cancel |
QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
connect(infoBox, SIGNAL(finished(int)),
this, SLOT(retryMessageBoxFinished(int)));
infoBox->show();
} else {
connectToClient();
}
}
void QmlProfilerClientManager::connectionStateChanged()
{
if (!d->connection)
return;
switch (d->connection->state()) {
case QAbstractSocket::UnconnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: disconnected");
break;
}
case QAbstractSocket::HostLookupState:
break;
case QAbstractSocket::ConnectingState: {
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: Connecting to debug server ...");
break;
}
case QAbstractSocket::ConnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: connected and running");
// notify the client recording status
clientRecordingChanged();
break;
}
case QAbstractSocket::ClosingState:
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: closing ...");
break;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
break;
}
}
void QmlProfilerClientManager::retryMessageBoxFinished(int result)
{
switch (result) {
case QMessageBox::Retry: {
d->connectionAttempts = 0;
d->connectionTimer.start();
break;
}
case QMessageBox::Help: {
QmlProfilerTool::handleHelpRequest(QString("qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html"));
// fall through
}
default: {
if (d->connection) {
QmlProfilerTool::logStatus("QML Profiler: Failed to connect! " + d->connection->errorString());
} else {
QmlProfilerTool::logStatus("QML Profiler: Failed to connect!");
}
emit connectionFailed();
break;
}
}
}
void QmlProfilerClientManager::qmlComplete()
{
d->qmlDataReady = true;
if (!d->v8clientplugin || d->v8clientplugin.data()->status() != QDeclarativeDebugClient::Enabled || d->v8DataReady) {
emit dataReadyForProcessing();
// once complete is sent, reset the flags
d->qmlDataReady = false;
d->v8DataReady = false;
}
}
void QmlProfilerClientManager::v8Complete()
{
d->v8DataReady = true;
if (!d->qmlclientplugin || d->qmlclientplugin.data()->status() != QDeclarativeDebugClient::Enabled || d->qmlDataReady) {
emit dataReadyForProcessing();
// once complete is sent, reset the flags
d->v8DataReady = false;
d->qmlDataReady = false;
}
}
void QmlProfilerClientManager::stopClientsRecording()
{
if (d->qmlclientplugin)
d->qmlclientplugin.data()->setRecording(false);
if (d->v8clientplugin)
d->v8clientplugin.data()->setRecording(false);
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerClientManager::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
if (d->profilerState) {
disconnect(d->profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
disconnect(d->profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
disconnect(d->profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
}
d->profilerState = profilerState;
// connect
if (d->profilerState) {
connect(d->profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
connect(d->profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
connect(d->profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
}
}
void QmlProfilerClientManager::profilerStateChanged()
{
QTC_ASSERT(d->profilerState, return);
switch (d->profilerState->currentState()) {
case QmlProfilerStateManager::AppStopRequested :
if (d->profilerState->serverRecording()) {
stopClientsRecording();
}
else
d->profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
break;
default:
break;
}
}
void QmlProfilerClientManager::clientRecordingChanged()
{
QTC_ASSERT(d->profilerState, return);
if (d->profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (d->qmlclientplugin)
d->qmlclientplugin.data()->setRecording(d->profilerState->clientRecording());
if (d->v8clientplugin)
d->v8clientplugin.data()->setRecording(d->profilerState->clientRecording());
}
}
void QmlProfilerClientManager::serverRecordingChanged()
{
if (d->profilerState->serverRecording()) {
d->v8DataReady = false;
d->qmlDataReady = false;
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -0,0 +1,102 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef QMLPROFILERCLIENTMANAGER_H
#define QMLPROFILERCLIENTMANAGER_H
#include <QObject>
#include <QStringList>
#include "qmlprofilerstatemanager.h"
#include <qmljsdebugclient/qmlprofilereventlocation.h>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerClientManager : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerClientManager(QObject *parent = 0);
~QmlProfilerClientManager();
void registerProfilerStateManager(QmlProfilerStateManager *profilerState);
void setTcpConnection(QString host, quint64 port);
void setOstConnection(QString ostDevice);
void clearBufferedData();
signals:
void connectionFailed();
// data
void addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation);
void addV8Event(int,QString,QString,int,double,double);
void addFrameEvent(qint64,int,int);
void traceStarted(qint64);
void traceFinished(qint64);
void dataReadyForProcessing();
public slots:
void connectClient(quint16 port);
void disconnectClient();
private slots:
void tryToConnect();
void connectionStateChanged();
void retryMessageBoxFinished(int result);
void qmlComplete();
void v8Complete();
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
private:
class QmlProfilerClientManagerPrivate;
QmlProfilerClientManagerPrivate *d;
void connectToClient();
void enableServices();
void connectClientSignals();
void disconnectClientSignals();
void stopClientsRecording();
};
}
}
#endif // QMLPROFILERCLIENTMANAGER_H

View File

@@ -37,6 +37,7 @@ namespace QmlProfiler {
namespace Constants {
const char ATTACH[] = "Menu.Analyzer.Attach";
const char TraceFileExtension[] = ".qtd";
} // namespace Constants
} // namespace QmlProfiler

File diff suppressed because it is too large Load Diff

View File

@@ -30,33 +30,37 @@
**
**************************************************************************/
#ifndef QMLPROFILEREVENTLIST_H
#define QMLPROFILEREVENTLIST_H
#ifndef QMLPROFILERDATAMODEL_H
#define QMLPROFILERDATAMODEL_H
#include "qmlprofilereventtypes.h"
#include "qmlprofilereventlocation.h"
#include "qmljsdebugclient_global.h"
#include <qmljsdebugclient/qmlprofilereventtypes.h>
#include <qmljsdebugclient/qmlprofilereventlocation.h>
#include "qv8profilerdatamodel.h"
#include <QHash>
#include <QObject>
namespace QmlJsDebugClient {
namespace QmlProfiler {
namespace Internal {
struct QmlEventSub;
struct QV8EventSub;
// used for parents and children
struct QmlRangeEventRelative;
struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
struct QmlRangeEventData
{
QmlEventData();
~QmlEventData();
QmlRangeEventData();
~QmlRangeEventData();
QString displayname;
int eventId;
QString displayName;
QString eventHashStr;
QString details;
QmlEventLocation location;
QmlJsDebugClient::QmlEventLocation location;
QmlJsDebugClient::QmlEventType eventType;
QHash <QString, QmlEventSub *> parentHash;
QHash <QString, QmlEventSub *> childrenHash;
QHash <QString, QmlRangeEventRelative *> parentHash;
QHash <QString, QmlRangeEventRelative *> childrenHash;
qint64 duration;
qint64 calls;
qint64 minTime;
@@ -64,54 +68,22 @@ struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
double timePerCall;
double percentOfTime;
qint64 medianTime;
int eventId;
bool isBindingLoop;
QmlEventData &operator=(const QmlEventData &ref);
QmlRangeEventData &operator=(const QmlRangeEventData &ref);
};
struct QMLJSDEBUGCLIENT_EXPORT QmlEventSub {
QmlEventSub(QmlEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
QmlEventSub(QmlEventSub *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
QmlEventData *reference;
struct QmlRangeEventRelative {
QmlRangeEventRelative(QmlRangeEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
QmlRangeEventRelative(QmlRangeEventRelative *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
QmlRangeEventData *reference;
qint64 duration;
qint64 calls;
bool inLoopPath;
};
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
{
QV8EventData();
~QV8EventData();
QString displayName;
QString filename;
QString functionName;
int line;
double totalTime; // given in milliseconds
double totalPercent;
double selfTime;
double selfPercent;
QHash <QString, QV8EventSub *> parentHash;
QHash <QString, QV8EventSub *> childrenHash;
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 QList<QmlEventData *> QmlEventDescriptions;
typedef QList<QV8EventData *> QV8EventDescriptions;
class QMLJSDEBUGCLIENT_EXPORT QmlProfilerEventList : public QObject
class QmlProfilerDataModel : public QObject
{
Q_OBJECT
public:
@@ -122,23 +94,30 @@ public:
Done
};
explicit QmlProfilerEventList(QObject *parent = 0);
~QmlProfilerEventList();
explicit QmlProfilerDataModel(QObject *parent = 0);
~QmlProfilerDataModel();
QmlEventDescriptions getEventDescriptions() const;
QmlEventData *eventDescription(int eventId) const;
const QV8EventDescriptions& getV8Events() const;
QList<QmlRangeEventData *> getEventDescriptions() const;
QmlRangeEventData *eventDescription(int eventId) const;
QList<QV8EventData *> getV8Events() const;
QV8EventData *v8EventDescription(int eventId) const;
static QString getHashStringForQmlEvent(const QmlJsDebugClient::QmlEventLocation &location, int eventType);
static QString getHashStringForV8Event(const QString &displayName, const QString &function);
static QString rootEventName();
static QString rootEventDescription();
static QString qmlEventTypeAsString(QmlJsDebugClient::QmlEventType typeEnum);
static QmlJsDebugClient::QmlEventType qmlEventTypeAsEnum(const QString &typeString);
int findFirstIndex(qint64 startTime) const;
int findFirstIndexNoParents(qint64 startTime) const;
int findLastIndex(qint64 endTime) const;
Q_INVOKABLE qint64 firstTimeMark() const;
Q_INVOKABLE qint64 lastTimeMark() const;
Q_INVOKABLE int count() const;
// data access
Q_INVOKABLE int count() const;
Q_INVOKABLE bool isEmpty() const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
Q_INVOKABLE qint64 getDuration(int index) const;
@@ -171,7 +150,6 @@ public:
Q_INVOKABLE qint64 qmlMeasuredTime() const;
Q_INVOKABLE qint64 v8MeasuredTime() const;
void showErrorDialog(const QString &st ) const;
void compileStatistics(qint64 startTime, qint64 endTime);
State currentState() const;
Q_INVOKABLE int getCurrentStateFromQml() const;
@@ -188,44 +166,37 @@ signals:
public slots:
void clear();
void addRangedEvent(int type, qint64 startTime, qint64 length,
const QStringList &data, const QmlJsDebugClient::QmlEventLocation &location);
void complete();
void addV8Event(int depth,const QString &function,const QString &filename, int lineNumber, double totalTime, double selfTime);
void addFrameEvent(qint64 time, int framerate, int animationcount);
void setTraceStartTime(qint64 time);
void setTraceEndTime(qint64 time);
void complete();
bool save(const QString &filename);
void load(const QString &filename);
void setFilename(const QString &filename);
void load();
void setTraceEndTime( qint64 time );
void setTraceStartTime( qint64 time );
void rewriteDetailsString(int eventType, const QmlJsDebugClient::QmlEventLocation &location, const QString &newString);
void finishedRewritingDetails();
private:
void postProcess();
void sortEndTimes();
void findAnimationLimits();
void sortStartTimes();
void computeLevels();
void computeNestingLevels();
void computeNestingDepth();
void prepareForDisplay();
void linkEndsToStarts();
void reloadDetails();
void findBindingLoops(qint64 startTime, qint64 endTime);
bool checkBindingLoop(QmlEventData *from, QmlEventData *current, QList<QmlEventData *>visited);
void setState(State state);
void reloadDetails();
private:
class QmlProfilerEventListPrivate;
QmlProfilerEventListPrivate *d;
class QmlProfilerDataModelPrivate;
QmlProfilerDataModelPrivate *d;
friend class QV8ProfilerDataModel;
};
} // namespace QmlJsDebugClient
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILEREVENTLIST_H
#endif // QMLPROFILERDATAMODEL_H

View File

@@ -35,7 +35,7 @@
#include <QObject>
#include "qmljsdebugclient/qmlprofilereventlocation.h"
#include <qmljsdebugclient/qmlprofilereventlocation.h>
#include <qmljs/qmljsdocument.h>
namespace QmlProfiler {

View File

@@ -35,8 +35,6 @@
#include "codaqmlprofilerrunner.h"
#include "localqmlprofilerrunner.h"
#include "remotelinuxqmlprofilerrunner.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilertool.h"
#include <analyzerbase/analyzermanager.h>
#include <coreplugin/icore.h>
@@ -76,16 +74,11 @@ public:
QmlProfilerEngine *q;
//AnalyzerStartParameters m_params;
QmlProfilerStateManager *m_profilerState;
AbstractQmlProfilerRunner *m_runner;
bool m_running;
bool m_fetchingData;
bool m_hasData;
bool m_fetchDataFromStart;
bool m_delayedDelete;
QTimer m_noDebugOutputTimer;
QmlJsDebugClient::QDeclarativeOutputParser m_outputParser;
QTimer m_runningTimer;
};
AbstractQmlProfilerRunner *
@@ -137,10 +130,7 @@ QmlProfilerEngine::QmlProfilerEngine(IAnalyzerTool *tool,
: IAnalyzerEngine(tool, sp, runConfiguration)
, d(new QmlProfilerEnginePrivate(this))
{
d->m_running = false;
d->m_fetchingData = false;
d->m_fetchDataFromStart = false;
d->m_delayedDelete = false;
d->m_profilerState = 0;
// Only wait 4 seconds for the 'Waiting for connection' on application ouput, then just try to connect
// (application output might be redirected / blocked)
@@ -157,29 +147,31 @@ QmlProfilerEngine::QmlProfilerEngine(IAnalyzerTool *tool,
this, SLOT(processIsRunning()));
connect(&d->m_outputParser, SIGNAL(errorMessage(QString)),
this, SLOT(wrongSetupMessageBox(QString)));
d->m_runningTimer.setInterval(100); // ten times per second
connect(&d->m_runningTimer, SIGNAL(timeout()), this, SIGNAL(timeUpdate()));
}
QmlProfilerEngine::~QmlProfilerEngine()
{
if (d->m_running)
if (d->m_profilerState && d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning)
stop();
delete d;
}
bool QmlProfilerEngine::start()
{
QTC_ASSERT(d->m_profilerState, return false);
if (d->m_runner) {
delete d->m_runner;
d->m_runner = 0;
}
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStarting);
if (QmlProjectManager::QmlProjectRunConfiguration *rc =
qobject_cast<QmlProjectManager::QmlProjectRunConfiguration *>(runConfiguration())) {
if (rc->observerPath().isEmpty()) {
QmlProjectManager::QmlProjectPlugin::showQmlObserverToolWarning();
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
AnalyzerManager::stopTool();
return false;
}
@@ -190,13 +182,14 @@ bool QmlProfilerEngine::start()
if (LocalQmlProfilerRunner *qmlRunner = qobject_cast<LocalQmlProfilerRunner *>(d->m_runner)) {
if (!qmlRunner->hasExecutable()) {
showNonmodalWarning(tr("No executable file to launch."));
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
AnalyzerManager::stopTool();
return false;
}
}
if (d->m_runner) {
connect(d->m_runner, SIGNAL(stopped()), this, SLOT(stopped()));
connect(d->m_runner, SIGNAL(stopped()), this, SLOT(processEnded()));
connect(d->m_runner, SIGNAL(appendMessage(QString,Utils::OutputFormat)),
this, SLOT(logApplicationMessage(QString,Utils::OutputFormat)));
d->m_runner->start();
@@ -205,81 +198,80 @@ bool QmlProfilerEngine::start()
emit processRunning(startParameters().connParams.port);
}
d->m_running = true;
d->m_delayedDelete = false;
d->m_runningTimer.start();
if (d->m_fetchDataFromStart) {
d->m_fetchingData = true;
d->m_hasData = false;
}
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning);
emit starting(this);
return true;
}
void QmlProfilerEngine::stop()
{
if (d->m_fetchingData) {
if (d->m_running)
d->m_delayedDelete = true;
// will result in dataReceived() call
emit stopRecording();
d->m_fetchDataFromStart = true;
} else {
finishProcess();
d->m_fetchDataFromStart = false;
QTC_ASSERT(d->m_profilerState, return);
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppRunning : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopRequested);
break;
}
case QmlProfilerStateManager::AppReadyToStop : {
cancelProcess();
break;
}
case QmlProfilerStateManager::AppKilled : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
break;
}
default:
qDebug() << tr("Unexpected engine stop from state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
break;
}
}
void QmlProfilerEngine::stopped()
void QmlProfilerEngine::processEnded()
{
// if it was killed, preserve recording flag
if (d->m_running)
d->m_fetchDataFromStart = d->m_fetchingData;
QTC_ASSERT(d->m_profilerState, return);
// user feedback
if (d->m_running && d->m_fetchingData && !d->m_hasData) {
showNonmodalWarning(tr("Application finished before loading profiled data.\n Please use the stop button instead."));
emit applicationDied();
}
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppRunning : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
AnalyzerManager::stopTool();
d->m_running = false;
d->m_runningTimer.stop();
AnalyzerManager::stopTool();
emit finished();
emit recordingChanged(d->m_fetchDataFromStart);
}
void QmlProfilerEngine::setFetchingData(bool b)
{
d->m_fetchingData = b;
if (d->m_running && b)
d->m_hasData = false;
if (!d->m_running)
d->m_fetchDataFromStart = b;
}
void QmlProfilerEngine::dataReceived()
{
if (d->m_delayedDelete)
finishProcess();
d->m_delayedDelete = false;
d->m_hasData = true;
}
void QmlProfilerEngine::finishProcess()
{
// user stop?
if (d->m_running) {
d->m_running = false;
d->m_runningTimer.stop();
if (d->m_runner)
d->m_runner->stop();
emit finished();
emit recordingChanged(d->m_fetchDataFromStart);
break;
}
case QmlProfilerStateManager::AppStopped :
// fallthrough
case QmlProfilerStateManager::AppKilled : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::Idle);
break;
}
default:
qDebug() << tr("Process died unexpectedly from state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
break;
}
}
void QmlProfilerEngine::cancelProcess()
{
QTC_ASSERT(d->m_profilerState, return);
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppReadyToStop : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppStopped);
break;
}
case QmlProfilerStateManager::AppRunning : {
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
break;
}
default: {
qDebug() << tr("Unexpected process termination requested with state %1 in %2:%3").arg(d->m_profilerState->currentStateAsString(), QString(__FILE__), QString::number(__LINE__));
return;
}
}
if (d->m_runner)
d->m_runner->stop();
emit finished();
}
void QmlProfilerEngine::logApplicationMessage(const QString &msg, Utils::OutputFormat format)
@@ -305,11 +297,10 @@ void QmlProfilerEngine::wrongSetupMessageBox(const QString &errorMessage)
infoBox->show();
d->m_running = false;
d->m_runningTimer.stop();
// KILL
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppKilled);
AnalyzerManager::stopTool();
emit finished();
emit recordingChanged(d->m_fetchDataFromStart);
}
void QmlProfilerEngine::wrongSetupMessageBoxFinished(int button)
@@ -348,5 +339,44 @@ void QmlProfilerEngine::processIsRunning(quint16 port)
emit processRunning(d->m_runner->debugPort());
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerEngine::registerProfilerStateManager( QmlProfilerStateManager *profilerState )
{
// disconnect old
if (d->m_profilerState) {
disconnect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
}
d->m_profilerState = profilerState;
// connect
if (d->m_profilerState) {
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
}
}
void QmlProfilerEngine::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppReadyToStop : {
cancelProcess();
break;
}
case QmlProfilerStateManager::Idle : {
// for some reason the engine is not deleted when it goes to idle
// a new one will be created on the next run, and this one will
// be only deleted if the new one is running the same app
// we need to explictly disconnect it here without expecting a deletion
// as it will not be run any more, otherwise we will get funny side effects
registerProfilerStateManager(0);
break;
}
default:
break;
}
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -34,6 +34,7 @@
#define QMLPROFILERENGINE_H
#include <analyzerbase/ianalyzerengine.h>
#include "qmlprofilerstatemanager.h"
#include <utils/outputformat.h>
namespace QmlProfiler {
@@ -49,29 +50,29 @@ public:
ProjectExplorer::RunConfiguration *runConfiguration);
~QmlProfilerEngine();
void registerProfilerStateManager( QmlProfilerStateManager *profilerState );
static void showNonmodalWarning(const QString &warningMsg);
signals:
void processRunning(quint16 port);
void stopRecording();
void timeUpdate();
void recordingChanged(bool recording);
void applicationDied();
public slots:
bool start();
void stop();
private slots:
void stopped();
void processEnded();
void setFetchingData(bool);
void dataReceived();
void finishProcess();
void cancelProcess();
void logApplicationMessage(const QString &msg, Utils::OutputFormat format);
void wrongSetupMessageBox(const QString &errorMessage);
void wrongSetupMessageBoxFinished(int);
void processIsRunning(quint16 port = 0);
private slots:
void profilerStateChanged();
private:
class QmlProfilerEnginePrivate;
QmlProfilerEnginePrivate *d;

View File

@@ -48,6 +48,11 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "qmlprofilerviewmanager.h"
#include "qmlprofilertool.h"
#include <QMenu>
#include <utils/qtcassert.h>
using namespace QmlJsDebugClient;
@@ -90,31 +95,63 @@ public:
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent) : QWidget(parent)
class QmlProfilerEventsWidget::QmlProfilerEventsWidgetPrivate
{
public:
QmlProfilerEventsWidgetPrivate(QmlProfilerEventsWidget *qq):q(qq) {}
~QmlProfilerEventsWidgetPrivate() {}
QmlProfilerEventsWidget *q;
Analyzer::IAnalyzerTool *m_profilerTool;
QmlProfilerViewManager *m_viewContainer;
QmlProfilerEventsMainView *m_eventTree;
QmlProfilerEventsParentsAndChildrenView *m_eventChildren;
QmlProfilerEventsParentsAndChildrenView *m_eventParents;
QmlProfilerDataModel *m_profilerDataModel;
bool m_globalStatsEnabled;
};
QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerDataModel *profilerDataModel )
: QWidget(parent), d(new QmlProfilerEventsWidgetPrivate(this))
{
setObjectName("QmlProfilerEventsView");
m_eventTree = new QmlProfilerEventsMainView(model, this);
m_eventTree->setViewType(QmlProfilerEventsMainView::EventsView);
connect(m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
connect(m_eventTree, SIGNAL(showEventInTimeline(int)), this, SIGNAL(showEventInTimeline(int)));
d->m_profilerDataModel = profilerDataModel;
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
this, SLOT(profilerDataModelStateChanged()));
m_eventChildren = new QmlProfilerEventsParentsAndChildrenView(model, QmlProfilerEventsParentsAndChildrenView::ChildrenView, this);
m_eventParents = new QmlProfilerEventsParentsAndChildrenView(model, QmlProfilerEventsParentsAndChildrenView::ParentsView, this);
connect(m_eventTree, SIGNAL(eventSelected(int)), m_eventChildren, SLOT(displayEvent(int)));
connect(m_eventTree, SIGNAL(eventSelected(int)), m_eventParents, SLOT(displayEvent(int)));
connect(m_eventChildren, SIGNAL(eventClicked(int)), m_eventTree, SLOT(selectEvent(int)));
connect(m_eventParents, SIGNAL(eventClicked(int)), m_eventTree, SLOT(selectEvent(int)));
d->m_eventTree = new QmlProfilerEventsMainView(QmlProfilerEventsMainView::EventsView, this, d->m_profilerDataModel);
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
connect(d->m_eventTree, SIGNAL(showEventInTimeline(int)), this, SIGNAL(showEventInTimeline(int)));
d->m_eventChildren = new QmlProfilerEventsParentsAndChildrenView(
QmlProfilerEventsParentsAndChildrenView::ChildrenView,
this,
d->m_profilerDataModel);
d->m_eventParents = new QmlProfilerEventsParentsAndChildrenView(
QmlProfilerEventsParentsAndChildrenView::ParentsView,
this,
d->m_profilerDataModel);
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
// widget arrangement
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0,0,0,0);
groupLayout->setSpacing(0);
Core::MiniSplitter *splitterVertical = new Core::MiniSplitter;
splitterVertical->addWidget(m_eventTree);
splitterVertical->addWidget(d->m_eventTree);
Core::MiniSplitter *splitterHorizontal = new Core::MiniSplitter;
splitterHorizontal->addWidget(m_eventParents);
splitterHorizontal->addWidget(m_eventChildren);
splitterHorizontal->addWidget(d->m_eventParents);
splitterHorizontal->addWidget(d->m_eventChildren);
splitterHorizontal->setOrientation(Qt::Horizontal);
splitterVertical->addWidget(splitterHorizontal);
splitterVertical->setOrientation(Qt::Vertical);
@@ -123,23 +160,21 @@ QmlProfilerEventsWidget::QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEv
groupLayout->addWidget(splitterVertical);
setLayout(groupLayout);
m_eventStatistics = model;
if (model) {
connect(model, SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
}
m_globalStatsEnabled = true;
d->m_profilerTool = profilerTool;
d->m_viewContainer = container;
d->m_globalStatsEnabled = true;
}
QmlProfilerEventsWidget::~QmlProfilerEventsWidget()
{
delete d;
}
void QmlProfilerEventsWidget::eventListStateChanged()
void QmlProfilerEventsWidget::profilerDataModelStateChanged()
{
if (m_eventStatistics) {
QmlProfilerEventList::State newState = m_eventStatistics->currentState();
if (newState == QmlProfilerEventList::Empty) {
if (d->m_profilerDataModel) {
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
if (newState == QmlProfilerDataModel::Empty) {
clear();
}
}
@@ -148,57 +183,119 @@ void QmlProfilerEventsWidget::eventListStateChanged()
void QmlProfilerEventsWidget::switchToV8View()
{
setObjectName("QmlProfilerV8ProfileView");
m_eventTree->setViewType(QmlProfilerEventsMainView::V8ProfileView);
m_eventParents->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ParentsView);
m_eventChildren->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ChildrenView);
d->m_eventTree->setViewType(QmlProfilerEventsMainView::V8ProfileView);
d->m_eventParents->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ParentsView);
d->m_eventChildren->setViewType(QmlProfilerEventsParentsAndChildrenView::V8ChildrenView);
setToolTip(tr("Trace information from the v8 JavaScript engine. Available only in Qt5 based applications"));
}
void QmlProfilerEventsWidget::clear()
{
m_eventTree->clear();
m_eventChildren->clear();
m_eventParents->clear();
d->m_eventTree->clear();
d->m_eventChildren->clear();
d->m_eventParents->clear();
}
void QmlProfilerEventsWidget::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
clear();
m_eventTree->getStatisticsInRange(rangeStart, rangeEnd);
m_globalStatsEnabled = m_eventTree->isRangeGlobal(rangeStart, rangeEnd);
d->m_eventTree->getStatisticsInRange(rangeStart, rangeEnd);
d->m_globalStatsEnabled = d->m_eventTree->isRangeGlobal(rangeStart, rangeEnd);
}
QModelIndex QmlProfilerEventsWidget::selectedItem() const
{
return m_eventTree->selectedItem();
return d->m_eventTree->selectedItem();
}
void QmlProfilerEventsWidget::contextMenuEvent(QContextMenuEvent *ev)
{
emit contextMenuRequested(ev->globalPos());
QTC_ASSERT(d->m_viewContainer, return;);
QMenu menu;
QAction *copyRowAction = 0;
QAction *copyTableAction = 0;
QAction *showExtendedStatsAction = 0;
QAction *getLocalStatsAction = 0;
QAction *getGlobalStatsAction = 0;
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
QPoint position = ev->globalPos();
if (profilerTool) {
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
foreach (QAction *act, commonActions) {
menu.addAction(act);
}
}
if (mouseOnTable(position)) {
menu.addSeparator();
if (selectedItem().isValid())
copyRowAction = menu.addAction(tr("Copy Row"));
copyTableAction = menu.addAction(tr("Copy Table"));
if (isQml()) {
// only for qml events view, not for v8
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
showExtendedStatsAction->setCheckable(true);
showExtendedStatsAction->setChecked(showExtendedStatistics());
}
}
if (isQml()) {
menu.addSeparator();
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
if (!d->m_viewContainer->hasValidSelection())
getLocalStatsAction->setEnabled(false);
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
if (hasGlobalStats())
getGlobalStatsAction->setEnabled(false);
}
QAction *selectedAction = menu.exec(position);
if (selectedAction) {
if (selectedAction == copyRowAction)
copyRowToClipboard();
if (selectedAction == copyTableAction)
copyTableToClipboard();
if (selectedAction == getLocalStatsAction) {
getStatisticsInRange(d->m_viewContainer->selectionStart(),
d->m_viewContainer->selectionEnd());
}
if (selectedAction == getGlobalStatsAction) {
if (d->m_profilerDataModel) {
getStatisticsInRange(d->m_profilerDataModel->traceStartTime(),
d->m_profilerDataModel->traceEndTime());
}
}
if (selectedAction == showExtendedStatsAction)
setShowExtendedStatistics(!showExtendedStatistics());
}
}
bool QmlProfilerEventsWidget::mouseOnTable(const QPoint &position) const
{
QPoint tableTopLeft = m_eventTree->mapToGlobal(QPoint(0,0));
QPoint tableBottomRight = m_eventTree->mapToGlobal(QPoint(m_eventTree->width(), m_eventTree->height()));
QPoint tableTopLeft = d->m_eventTree->mapToGlobal(QPoint(0,0));
QPoint tableBottomRight = d->m_eventTree->mapToGlobal(QPoint(d->m_eventTree->width(), d->m_eventTree->height()));
return (position.x() >= tableTopLeft.x() && position.x() <= tableBottomRight.x() && position.y() >= tableTopLeft.y() && position.y() <= tableBottomRight.y());
}
void QmlProfilerEventsWidget::copyTableToClipboard() const
{
m_eventTree->copyTableToClipboard();
d->m_eventTree->copyTableToClipboard();
}
void QmlProfilerEventsWidget::copyRowToClipboard() const
{
m_eventTree->copyRowToClipboard();
d->m_eventTree->copyRowToClipboard();
}
void QmlProfilerEventsWidget::updateSelectedEvent(int eventId) const
{
if (m_eventTree->selectedEventId() != eventId)
m_eventTree->selectEvent(eventId);
if (d->m_eventTree->selectedEventId() != eventId)
d->m_eventTree->selectEvent(eventId);
}
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
@@ -207,22 +304,31 @@ void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, in
// Our javascript trace data does not store column information
// thus we ignore it here
Q_UNUSED(column);
m_eventTree->selectEventByLocation(filename, line);
d->m_eventTree->selectEventByLocation(filename, line);
}
bool QmlProfilerEventsWidget::hasGlobalStats() const
{
return m_globalStatsEnabled;
return d->m_globalStatsEnabled;
}
void QmlProfilerEventsWidget::setShowExtendedStatistics(bool show)
{
m_eventTree->setShowExtendedStatistics(show);
d->m_eventTree->setShowExtendedStatistics(show);
}
bool QmlProfilerEventsWidget::showExtendedStatistics() const
{
return m_eventTree->showExtendedStatistics();
return d->m_eventTree->showExtendedStatistics();
}
bool QmlProfilerEventsWidget::isQml() const
{
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::EventsView;
}
bool QmlProfilerEventsWidget::isV8() const
{
return d->m_eventTree->viewType() == QmlProfilerEventsMainView::V8ProfileView;
}
////////////////////////////////////////////////////////////////////////////////////
@@ -232,8 +338,8 @@ class QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate
public:
QmlProfilerEventsMainViewPrivate(QmlProfilerEventsMainView *qq) : q(qq) {}
void buildModelFromList(const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList = QmlEventDescriptions() );
void buildV8ModelFromList( const QV8EventDescriptions &list );
void buildModelFromList(const QList<QmlRangeEventData *> &list, QStandardItem *parentItem );
void buildV8ModelFromList( const QList<QV8EventData *> &list );
int getFieldCount();
QString textForItem(QStandardItem *item, bool recursive) const;
@@ -242,7 +348,7 @@ public:
QmlProfilerEventsMainView *q;
QmlProfilerEventsMainView::ViewTypes m_viewType;
QmlProfilerEventList *m_eventStatistics;
QmlProfilerDataModel *m_profilerDataModel;
QStandardItemModel *m_model;
QList<bool> m_fieldShown;
QHash<int, int> m_columnIndex; // maps field enum to column index
@@ -254,8 +360,10 @@ public:
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventsMainView::QmlProfilerEventsMainView(QmlProfilerEventList *model, QWidget *parent) :
QTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
QmlProfilerEventsMainView::QmlProfilerEventsMainView(ViewTypes viewType,
QWidget *parent,
QmlProfilerDataModel *dataModel)
: QTreeView(parent), d(new QmlProfilerEventsMainViewPrivate(this))
{
setObjectName("QmlProfilerEventsTable");
header()->setResizeMode(QHeaderView::Interactive);
@@ -268,15 +376,17 @@ QmlProfilerEventsMainView::QmlProfilerEventsMainView(QmlProfilerEventList *model
setModel(d->m_model);
connect(this,SIGNAL(clicked(QModelIndex)), this,SLOT(jumpToItem(QModelIndex)));
d->m_eventStatistics = 0;
setEventStatisticsModel(model);
d->m_profilerDataModel = dataModel;
connect(d->m_profilerDataModel,SIGNAL(stateChanged()),
this,SLOT(profilerDataModelStateChanged()));
connect(d->m_profilerDataModel,SIGNAL(detailsChanged(int,QString)),
this,SLOT(changeDetailsForEvent(int,QString)));
d->m_firstNumericColumn = 0;
d->m_preventSelectBounce = false;
d->m_showExtendedStatistics = false;
// default view
setViewType(EventsView);
setViewType(viewType);
}
QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
@@ -285,24 +395,11 @@ QmlProfilerEventsMainView::~QmlProfilerEventsMainView()
delete d->m_model;
}
void QmlProfilerEventsMainView::setEventStatisticsModel( QmlProfilerEventList *model )
void QmlProfilerEventsMainView::profilerDataModelStateChanged()
{
if (d->m_eventStatistics) {
disconnect(d->m_eventStatistics,SIGNAL(stateChanged()),this,SLOT(eventListStateChanged()));
disconnect(d->m_eventStatistics,SIGNAL(detailsChanged(int,QString)),this,SLOT(changeDetailsForEvent(int,QString)));
}
d->m_eventStatistics = model;
if (model) {
connect(d->m_eventStatistics,SIGNAL(stateChanged()),this,SLOT(eventListStateChanged()));
connect(d->m_eventStatistics,SIGNAL(detailsChanged(int,QString)),this,SLOT(changeDetailsForEvent(int,QString)));
}
}
void QmlProfilerEventsMainView::eventListStateChanged()
{
if (d->m_eventStatistics) {
QmlProfilerEventList::State newState = d->m_eventStatistics->currentState();
if (newState == QmlProfilerEventList::Done)
if (d->m_profilerDataModel) {
QmlProfilerDataModel::State newState = d->m_profilerDataModel->currentState();
if (newState == QmlProfilerDataModel::Done)
buildModel();
}
}
@@ -319,6 +416,11 @@ void QmlProfilerEventsMainView::setFieldViewable(Fields field, bool show)
}
}
QmlProfilerEventsMainView::ViewTypes QmlProfilerEventsMainView::viewType() const
{
return d->m_viewType;
}
void QmlProfilerEventsMainView::setViewType(ViewTypes type)
{
d->m_viewType = type;
@@ -465,12 +567,12 @@ int QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::getFieldCount()
void QmlProfilerEventsMainView::buildModel()
{
if (d->m_eventStatistics) {
if (d->m_profilerDataModel) {
clear();
if (d->m_viewType == V8ProfileView)
d->buildV8ModelFromList( d->m_eventStatistics->getV8Events() );
d->buildV8ModelFromList( d->m_profilerDataModel->getV8Events() );
else
d->buildModelFromList( d->m_eventStatistics->getEventDescriptions(), d->m_model->invisibleRootItem() );
d->buildModelFromList( d->m_profilerDataModel->getEventDescriptions(), d->m_model->invisibleRootItem() );
setShowExtendedStatistics(d->m_showExtendedStatistics);
@@ -488,18 +590,15 @@ void QmlProfilerEventsMainView::buildModel()
}
}
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFromList( const QmlEventDescriptions &list, QStandardItem *parentItem, const QmlEventDescriptions &visitedFunctionsList )
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFromList( const QList<QmlRangeEventData *> &list, QStandardItem *parentItem)
{
foreach (QmlEventData *binding, list) {
if (visitedFunctionsList.contains(binding))
continue;
foreach (QmlRangeEventData *binding, list) {
if (binding->calls == 0)
continue;
QList<QStandardItem *> newRow;
if (m_fieldShown[Name]) {
newRow << new EventsViewItem(binding->displayname);
newRow << new EventsViewItem(binding->displayName);
}
if (m_fieldShown[Type]) {
@@ -572,7 +671,7 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
}
}
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFromList(const QV8EventDescriptions &list)
void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildV8ModelFromList(const QList<QV8EventData *> &list)
{
for (int index = 0; index < list.count(); index++) {
QV8EventData *v8event = list.at(index);
@@ -649,13 +748,17 @@ QString QmlProfilerEventsMainView::nameForType(int typeNumber)
void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
d->m_eventStatistics->compileStatistics(rangeStart, rangeEnd);
if (d->m_profilerDataModel)
d->m_profilerDataModel->compileStatistics(rangeStart, rangeEnd);
buildModel();
}
bool QmlProfilerEventsMainView::isRangeGlobal(qint64 rangeStart, qint64 rangeEnd) const
{
return d->m_eventStatistics->traceStartTime() == rangeStart && d->m_eventStatistics->traceEndTime() == rangeEnd;
if (d->m_profilerDataModel)
return d->m_profilerDataModel->traceStartTime() == rangeStart && d->m_profilerDataModel->traceEndTime() == rangeEnd;
else
return true;
}
int QmlProfilerEventsMainView::selectedEventId() const
@@ -691,7 +794,7 @@ void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
// show in callers/callees subwindow
emit eventSelected(infoItem->data(EventIdRole).toInt());
// show in timelineview
// show in timelinerenderer
if (d->m_viewType == EventsView) {
emit showEventInTimeline(infoItem->data(EventIdRole).toInt());
}
@@ -819,9 +922,11 @@ void QmlProfilerEventsMainView::copyRowToClipboard() const
////////////////////////////////////////////////////////////////////////////////////
QmlProfilerEventsParentsAndChildrenView::QmlProfilerEventsParentsAndChildrenView(QmlJsDebugClient::QmlProfilerEventList *model, SubViewType subtableType, QWidget *parent):QTreeView(parent)
QmlProfilerEventsParentsAndChildrenView::QmlProfilerEventsParentsAndChildrenView(
SubViewType subtableType, QWidget *parent, QmlProfilerDataModel *model)
: QTreeView(parent)
{
m_eventList = model;
m_profilerDataModel = model;
setModel(new QStandardItemModel(this));
setRootIsDecorated(false);
setFrameStyle(QFrame::NoFrame);
@@ -843,30 +948,33 @@ void QmlProfilerEventsParentsAndChildrenView::setViewType(SubViewType type)
void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
{
if (!m_profilerDataModel)
return;
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
bool isChildren = m_subtableType == ChildrenView || m_subtableType == V8ChildrenView;
if (isV8) {
QmlJsDebugClient::QV8EventData *v8event = m_eventList->v8EventDescription(eventId);
QV8EventData *v8event = m_profilerDataModel->v8EventDescription(eventId);
if (v8event) {
if (isChildren) {
QList <QmlJsDebugClient::QV8EventSub *> childrenList = v8event->childrenHash.values();
QList <QV8EventSub *> childrenList = v8event->childrenHash.values();
rebuildTree((QObject *)&childrenList);
}
else {
QList <QmlJsDebugClient::QV8EventSub *> parentList = v8event->parentHash.values();
QList <QV8EventSub *> parentList = v8event->parentHash.values();
rebuildTree((QObject *)&parentList);
}
}
} else {
QmlJsDebugClient::QmlEventData *qmlEvent = m_eventList->eventDescription(eventId);
QmlRangeEventData *qmlEvent = m_profilerDataModel->eventDescription(eventId);
if (qmlEvent) {
if (isChildren) {
QList <QmlJsDebugClient::QmlEventSub *> childrenList = qmlEvent->childrenHash.values();
QList <QmlRangeEventRelative *> childrenList = qmlEvent->childrenHash.values();
rebuildTree((QObject *)&childrenList);
}
else {
QList <QmlJsDebugClient::QmlEventSub *> parentList = qmlEvent->parentHash.values();
QList <QmlRangeEventRelative *> parentList = qmlEvent->parentHash.values();
rebuildTree((QObject *)&parentList);
}
}
@@ -881,7 +989,7 @@ void QmlProfilerEventsParentsAndChildrenView::displayEvent(int eventId)
sortByColumn(2);
}
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *profilerDataModel)
{
Q_ASSERT(treeModel());
treeModel()->clear();
@@ -889,8 +997,8 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
bool isV8 = m_subtableType == V8ParentsView || m_subtableType == V8ChildrenView;
QList <QmlEventSub *> *qmlList = static_cast< QList <QmlEventSub *> *>(eventList);
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(eventList);
QList <QmlRangeEventRelative *> *qmlList = static_cast< QList <QmlRangeEventRelative *> *>(profilerDataModel);
QList <QV8EventSub*> *v8List = static_cast< QList <QV8EventSub *> *>(profilerDataModel);
int listLength;
if (!isV8)
@@ -901,9 +1009,9 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
for (int index=0; index < listLength; index++) {
QList<QStandardItem *> newRow;
if (!isV8) {
QmlEventSub *event = qmlList->at(index);
QmlRangeEventRelative *event = qmlList->at(index);
newRow << new EventsViewItem(event->reference->displayname);
newRow << new EventsViewItem(event->reference->displayName);
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event->reference->eventType));
newRow << new EventsViewItem(QmlProfilerEventsMainView::displayTime(event->duration));
newRow << new EventsViewItem(QString::number(event->calls));

View File

@@ -34,9 +34,13 @@
#define QMLPROFILEREVENTVIEW_H
#include <QTreeView>
#include <qmljsdebugclient/qmlprofilereventtypes.h>
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <QStandardItemModel>
#include <qmljsdebugclient/qmlprofilereventtypes.h>
#include "qmlprofilerdatamodel.h"
#include <analyzerbase/ianalyzertool.h>
#include "qmlprofilerviewmanager.h"
namespace QmlProfiler {
namespace Internal {
@@ -44,9 +48,6 @@ namespace Internal {
class QmlProfilerEventsMainView;
class QmlProfilerEventsParentsAndChildrenView;
typedef QHash<QString, QmlJsDebugClient::QmlEventData *> QmlEventHash;
typedef QList<QmlJsDebugClient::QmlEventData *> QmlEventList;
enum ItemRole {
EventHashStrRole = Qt::UserRole+1,
FilenameRole = Qt::UserRole+2,
@@ -59,7 +60,10 @@ class QmlProfilerEventsWidget : public QWidget
{
Q_OBJECT
public:
explicit QmlProfilerEventsWidget(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent);
explicit QmlProfilerEventsWidget(QWidget *parent,
Analyzer::IAnalyzerTool *profilerTool,
QmlProfilerViewManager *container,
QmlProfilerDataModel *profilerDataModel );
~QmlProfilerEventsWidget();
void switchToV8View();
@@ -75,9 +79,11 @@ public:
void setShowExtendedStatistics(bool show);
bool showExtendedStatistics() const;
bool isQml() const;
bool isV8() const;
signals:
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
void contextMenuRequested(const QPoint &position);
void showEventInTimeline(int eventId);
public slots:
@@ -85,18 +91,14 @@ public slots:
void selectBySourceLocation(const QString &filename, int line, int column);
private slots:
void eventListStateChanged();
void profilerDataModelStateChanged();
protected:
void contextMenuEvent(QContextMenuEvent *ev);
private:
QmlProfilerEventsMainView *m_eventTree;
QmlProfilerEventsParentsAndChildrenView *m_eventChildren;
QmlProfilerEventsParentsAndChildrenView *m_eventParents;
QmlJsDebugClient::QmlProfilerEventList *m_eventStatistics;
bool m_globalStatsEnabled;
class QmlProfilerEventsWidgetPrivate;
QmlProfilerEventsWidgetPrivate *d;
};
class QmlProfilerEventsMainView : public QTreeView
@@ -129,12 +131,14 @@ public:
MaxViewTypes
};
explicit QmlProfilerEventsMainView(QmlJsDebugClient::QmlProfilerEventList *model, QWidget *parent);
explicit QmlProfilerEventsMainView(ViewTypes viewType,
QWidget *parent,
QmlProfilerDataModel *dataModel);
~QmlProfilerEventsMainView();
void setEventStatisticsModel(QmlJsDebugClient::QmlProfilerEventList *model);
void setFieldViewable(Fields field, bool show);
void setViewType(ViewTypes type);
ViewTypes viewType() const;
void setShowAnonymousEvents( bool showThem );
QModelIndex selectedItem() const;
@@ -157,7 +161,6 @@ signals:
void showEventInTimeline(int eventId);
public slots:
void eventListStateChanged();
void clear();
void jumpToItem(const QModelIndex &index);
void selectEvent(int eventId);
@@ -165,6 +168,9 @@ public slots:
void buildModel();
void changeDetailsForEvent(int eventId, const QString &newString);
private slots:
void profilerDataModelStateChanged();
private:
void setHeaderLabels();
@@ -186,7 +192,9 @@ public:
MaxSubtableTypes
};
explicit QmlProfilerEventsParentsAndChildrenView(QmlJsDebugClient::QmlProfilerEventList *model, SubViewType subtableType, QWidget *parent);
explicit QmlProfilerEventsParentsAndChildrenView(SubViewType subtableType,
QWidget *parent,
QmlProfilerDataModel *model);
~QmlProfilerEventsParentsAndChildrenView();
void setViewType(SubViewType type);
@@ -200,10 +208,10 @@ public slots:
void clear();
private:
void rebuildTree(void *eventList);
void rebuildTree(void *profilerDataModel);
void updateHeader();
QStandardItemModel *treeModel();
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
QmlProfilerDataModel *m_profilerDataModel;
SubViewType m_subtableType;
};

View File

@@ -0,0 +1,163 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmlprofilerstatemanager.h"
#include <QDebug>
#include <utils/qtcassert.h>
// uncomment for printing the state changes to debug output
//#define _DEBUG_PROFILERSTATE_
namespace QmlProfiler {
namespace Internal {
inline QString stringForState(int state) {
switch (state) {
case QmlProfilerStateManager::Idle: return QString("Idle");
case QmlProfilerStateManager::AppStarting: return QString("AppStarting");
case QmlProfilerStateManager::AppRunning: return QString("AppRunning");
case QmlProfilerStateManager::AppStopRequested: return QString("AppStopRequested");
case QmlProfilerStateManager::AppReadyToStop: return QString("AppReadyToStop");
case QmlProfilerStateManager::AppStopped: return QString("AppStopped");
case QmlProfilerStateManager::AppKilled: return QString("AppKilled");
default: break;
}
return QString();
}
class QmlProfilerStateManager::QmlProfilerStateManagerPrivate
{
public:
QmlProfilerStateManagerPrivate(QmlProfilerStateManager *qq) : q(qq) {}
~QmlProfilerStateManagerPrivate() {}
QmlProfilerStateManager *q;
QmlProfilerStateManager::QmlProfilerState m_currentState;
bool m_clientRecording;
bool m_serverRecording;
};
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
QObject(parent),d(new QmlProfilerStateManagerPrivate(this))
{
d->m_currentState = Idle;
d->m_clientRecording = true;
d->m_serverRecording = false;
}
QmlProfilerStateManager::~QmlProfilerStateManager()
{
delete d;
}
QmlProfilerStateManager::QmlProfilerState QmlProfilerStateManager::currentState()
{
return d->m_currentState;
}
bool QmlProfilerStateManager::clientRecording()
{
return d->m_clientRecording;
}
bool QmlProfilerStateManager::serverRecording()
{
return d->m_serverRecording;
}
QString QmlProfilerStateManager::currentStateAsString()
{
return stringForState(d->m_currentState);
}
void QmlProfilerStateManager::setCurrentState(QmlProfilerState newState)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Profiler state change request from" << stringForState(d->m_currentState) << "to" << stringForState(newState);
#endif
QTC_ASSERT(d->m_currentState != newState, /**/);
switch (newState) {
case Idle:
QTC_ASSERT(d->m_currentState == AppStarting || d->m_currentState == AppStopped || d->m_currentState == AppKilled, /**/);
break;
case AppStarting:
QTC_ASSERT(d->m_currentState == Idle, /**/);
break;
case AppRunning:
QTC_ASSERT(d->m_currentState == AppStarting, /**/);
break;
case AppStopRequested:
QTC_ASSERT(d->m_currentState == AppRunning, /**/);
break;
case AppReadyToStop:
QTC_ASSERT(d->m_currentState == AppStopRequested, /**/);
break;
case AppStopped:
QTC_ASSERT(d->m_currentState == AppReadyToStop, /**/);
break;
case AppKilled:
QTC_ASSERT(d->m_currentState == AppRunning, /**/);
break;
default:
qDebug() << tr("Switching to unknown state in %1:%2").arg(QString(__FILE__), QString::number(__LINE__));
break;
}
d->m_currentState = newState;
emit stateChanged();
}
void QmlProfilerStateManager::setClientRecording(bool recording)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Setting client recording flag from" << d->m_serverRecording << "to" << recording;
#endif
if (d->m_clientRecording != recording) {
d->m_clientRecording = recording;
emit clientRecordingChanged();
}
}
void QmlProfilerStateManager::setServerRecording(bool recording)
{
#ifdef _DEBUG_PROFILERSTATE_
qDebug() << "Setting server recording flag from" << d->m_serverRecording << "to" << recording;
#endif
if (d->m_serverRecording != recording) {
d->m_serverRecording = recording;
emit serverRecordingChanged();
}
}
}
}

View File

@@ -30,25 +30,53 @@
**
**************************************************************************/
#ifndef COMMANDLISTENER_H
#define COMMANDLISTENER_H
#ifndef QMLPROFILERSTATEMANAGER_H
#define QMLPROFILERSTATEMANAGER_H
#include <QThread>
#include <QObject>
class CommandListener : public QThread
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateManager : public QObject
{
Q_OBJECT
public:
CommandListener(QObject *parent = 0);
enum QmlProfilerState {
Idle,
AppStarting,
AppRunning,
AppStopRequested,
AppReadyToStop,
AppStopped,
AppKilled
};
void run();
explicit QmlProfilerStateManager(QObject *parent = 0);
~QmlProfilerStateManager();
QmlProfilerState currentState();
bool clientRecording();
bool serverRecording();
QString currentStateAsString();
void requestStop() { m_stopRequested = true; }
signals:
void command(const QString &command);
void stateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
public slots:
void setCurrentState(QmlProfilerState newState);
void setClientRecording(bool recording);
void setServerRecording(bool recording);
private:
bool m_stopRequested;
class QmlProfilerStateManagerPrivate;
QmlProfilerStateManagerPrivate *d;
};
#endif // COMMANDLISTENER_H
}
}
#endif // QMLPROFILERSTATEMANAGER_H

View File

@@ -31,24 +31,20 @@
**************************************************************************/
#include "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilerengine.h"
#include "qmlprofilerplugin.h"
#include "qmlprofilerconstants.h"
#include "qmlprofilerattachdialog.h"
#include "qmlprofilereventview.h"
#include "tracewindow.h"
#include "timelineview.h"
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <qmljsdebugclient/qdeclarativedebugclient.h>
#include "qmlprofilerviewmanager.h"
#include "qmlprofilerclientmanager.h"
#include "qmlprofilerdatamodel.h"
#include "qmlprofilerdetailsrewriter.h"
#include "timelinerenderer.h"
#include <analyzerbase/analyzermanager.h>
#include <analyzerbase/analyzerconstants.h>
#include <analyzerbase/analyzerruncontrol.h>
#include "canvas/qdeclarativecanvas_p.h"
#include "canvas/qdeclarativecanvastimer_p.h"
#include "canvas/qdeclarativecontext2d_p.h"
#include "canvas/qmlprofilercanvas.h"
#include <qmlprojectmanager/qmlprojectrunconfiguration.h>
@@ -56,7 +52,6 @@
#include <utils/fileinprojectfinder.h>
#include <utils/qtcassert.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <projectexplorer/session.h>
@@ -65,7 +60,6 @@
#include <remotelinux/remotelinuxrunconfiguration.h>
#include <remotelinux/linuxdeviceconfiguration.h>
#include <texteditor/itexteditor.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
@@ -82,23 +76,22 @@
#include <qt4projectmanager/qt-s60/s60devicerunconfiguration.h>
#include <qt4projectmanager/qt-s60/s60deployconfiguration.h>
#include <QFile>
#include <QApplication>
#include <QHBoxLayout>
#include <QLabel>
#include <QTabWidget>
#include <QToolButton>
#include <QMessageBox>
#include <QDockWidget>
#include <QFileDialog>
#include <QMenu>
#include <QTimer>
#include <QTime>
using namespace Core;
using namespace Core::Constants;
using namespace Analyzer;
using namespace Analyzer::Constants;
using namespace QmlProfiler::Internal;
using namespace QmlProfiler::Constants;
using namespace QmlJsDebugClient;
using namespace ProjectExplorer;
using namespace QmlProjectManager;
@@ -112,59 +105,67 @@ public:
QmlProfilerTool *q;
QDeclarativeDebugConnection *m_client;
QTimer m_connectionTimer;
int m_connectionAttempts;
TraceWindow *m_traceWindow;
QmlProfilerEventsWidget *m_eventsView;
QmlProfilerEventsWidget *m_v8profilerView;
QmlProfilerStateManager *m_profilerState;
QmlProfilerClientManager *m_profilerConnections;
QmlProfilerDataModel *m_profilerDataModel;
QmlProfilerDetailsRewriter *m_detailsRewriter;
QmlProfilerViewManager *m_viewContainer;
Utils::FileInProjectFinder m_projectFinder;
RunConfiguration *m_runConfiguration;
bool m_isAttached;
QToolButton *m_recordButton;
QToolButton *m_clearButton;
bool m_recordingEnabled;
bool m_appIsRunning;
bool m_qmlActive;
bool m_v8Active;
QTime m_appTimer;
qint64 m_appRunningTime;
enum ConnectMode {
TcpConnection, OstConnection
};
// elapsed time display
QTimer m_recordingTimer;
QTime m_recordingElapsedTime;
QLabel *m_timeLabel;
ConnectMode m_connectMode;
QString m_tcpHost;
quint16 m_tcpPort;
QString m_ostDevice;
QString m_sysroot;
// save and load actions
QAction *m_saveQmlTrace;
QAction *m_loadQmlTrace;
};
QmlProfilerTool::QmlProfilerTool(QObject *parent)
: IAnalyzerTool(parent), d(new QmlProfilerToolPrivate(this))
{
setObjectName("QmlProfilerTool");
d->m_client = 0;
d->m_connectionAttempts = 0;
d->m_traceWindow = 0;
d->m_profilerState = 0;
d->m_viewContainer = 0;
d->m_runConfiguration = 0;
d->m_isAttached = false;
d->m_recordingEnabled = true;
d->m_appIsRunning = false;
d->m_appTimer.start();
d->m_appRunningTime = 0;
d->m_connectionTimer.setInterval(200);
connect(&d->m_connectionTimer, SIGNAL(timeout()), SLOT(tryToConnect()));
qmlRegisterType<Canvas>("Monitor", 1, 0, "Canvas");
qmlRegisterType<QmlProfilerCanvas>("Monitor", 1, 0, "Canvas2D");
qmlRegisterType<Context2D>();
qmlRegisterType<CanvasImage>();
qmlRegisterType<CanvasGradient>();
qmlRegisterType<TimelineView>("Monitor", 1, 0,"TimelineView");
qmlRegisterType<TimelineRenderer>("Monitor", 1, 0,"TimelineRenderer");
d->m_profilerState = new QmlProfilerStateManager(this);
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()), this, SLOT(clientRecordingChanged()));
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()), this, SLOT(serverRecordingChanged()));
d->m_profilerConnections = new QmlProfilerClientManager(this);
d->m_profilerConnections->registerProfilerStateManager(d->m_profilerState);
d->m_profilerDataModel = new QmlProfilerDataModel(this);
connect(d->m_profilerDataModel, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
connect(d->m_profilerDataModel, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
connect(d->m_profilerConnections, SIGNAL(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)), d->m_profilerDataModel, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
connect(d->m_profilerConnections, SIGNAL(addV8Event(int,QString,QString,int,double,double)), d->m_profilerDataModel, SLOT(addV8Event(int,QString,QString,int,double,double)));
connect(d->m_profilerConnections, SIGNAL(addFrameEvent(qint64,int,int)), d->m_profilerDataModel, SLOT(addFrameEvent(qint64,int,int)));
connect(d->m_profilerConnections, SIGNAL(traceStarted(qint64)), d->m_profilerDataModel, SLOT(setTraceStartTime(qint64)));
connect(d->m_profilerConnections, SIGNAL(traceFinished(qint64)), d->m_profilerDataModel, SLOT(setTraceEndTime(qint64)));
connect(d->m_profilerConnections, SIGNAL(dataReadyForProcessing()), d->m_profilerDataModel, SLOT(complete()));
d->m_detailsRewriter = new QmlProfilerDetailsRewriter(this);
connect(d->m_profilerDataModel, SIGNAL(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)),
d->m_detailsRewriter, SLOT(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)));
connect(d->m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)),
d->m_profilerDataModel, SLOT(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)));
connect(d->m_detailsRewriter, SIGNAL(eventDetailsChanged()), d->m_profilerDataModel, SLOT(finishedRewritingDetails()));
connect(d->m_profilerDataModel, SIGNAL(reloadDocumentsForDetails()), d->m_detailsRewriter, SLOT(reloadDocuments()));
Command *command = 0;
const Context globalContext(C_GLOBAL);
@@ -176,7 +177,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
menu->addMenu(options, G_ANALYZER_OPTIONS);
options->menu()->setEnabled(true);
QAction *act = new QAction(tr("Load QML Trace"), options);
QAction *act = d->m_loadQmlTrace = new QAction(tr("Load QML Trace"), options);
command = am->registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.LoadQMLTrace", globalContext);
connect(act, SIGNAL(triggered()), this, SLOT(showLoadDialog()));
options->addAction(command);
@@ -186,11 +187,13 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
command = am->registerAction(act, "Analyzer.Menu.StartAnalyzer.QMLProfilerOptions.SaveQMLTrace", globalContext);
connect(act, SIGNAL(triggered()), this, SLOT(showSaveDialog()));
options->addAction(command);
d->m_recordingTimer.setInterval(100);
connect(&d->m_recordingTimer, SIGNAL(timeout()), this, SLOT(updateTimeDisplay()));
}
QmlProfilerTool::~QmlProfilerTool()
{
delete d->m_client;
delete d;
}
@@ -220,86 +223,14 @@ IAnalyzerTool::ToolMode QmlProfilerTool::toolMode() const
return AnyMode;
}
void QmlProfilerTool::showContextMenu(const QPoint &position)
{
QmlProfilerEventsWidget *eventView = qobject_cast<QmlProfilerEventsWidget *>(sender());
TraceWindow *traceView = qobject_cast<TraceWindow *>(sender());
QMenu menu;
QAction *loadAction = menu.addAction(tr("Load QML Trace"));
QAction *saveAction = menu.addAction(tr("Save QML Trace"));
QAction *copyRowAction = 0;
QAction *copyTableAction = 0;
QAction *showExtendedStatsAction = 0;
QAction *viewAllAction = 0;
QAction *getLocalStatsAction = 0;
QAction *getGlobalStatsAction = 0;
if (eventView && eventView->mouseOnTable(position)) {
menu.addSeparator();
if (eventView->selectedItem().isValid())
copyRowAction = menu.addAction(tr("Copy Row"));
copyTableAction = menu.addAction(tr("Copy Table"));
if (eventView == d->m_eventsView) {
// only for qml events view, not for v8
showExtendedStatsAction = menu.addAction(tr("Extended Event Statistics"));
showExtendedStatsAction->setCheckable(true);
showExtendedStatsAction->setChecked(eventView->showExtendedStatistics());
}
}
if (sender() == d->m_traceWindow || sender() == d->m_eventsView) {
menu.addSeparator();
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
if (!d->m_traceWindow->hasValidSelection())
getLocalStatsAction->setEnabled(false);
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
if (d->m_eventsView->hasGlobalStats())
getGlobalStatsAction->setEnabled(false);
}
if (traceView) {
if (traceView->getEventList()->count() > 0) {
menu.addSeparator();
viewAllAction = menu.addAction(tr("Reset Zoom"));
}
}
QAction *selectedAction = menu.exec(position);
if (selectedAction) {
if (selectedAction == loadAction)
showLoadDialog();
if (selectedAction == saveAction)
showSaveDialog();
if (selectedAction == copyRowAction)
eventView->copyRowToClipboard();
if (selectedAction == copyTableAction)
eventView->copyTableToClipboard();
if (selectedAction == viewAllAction)
traceView->viewAll();
if (selectedAction == getLocalStatsAction) {
d->m_eventsView->getStatisticsInRange(
d->m_traceWindow->selectionStart(),
d->m_traceWindow->selectionEnd());
}
if (selectedAction == getGlobalStatsAction) {
d->m_eventsView->getStatisticsInRange(
d->m_traceWindow->getEventList()->traceStartTime(),
d->m_traceWindow->getEventList()->traceEndTime());
}
if (selectedAction == showExtendedStatsAction)
eventView->setShowExtendedStatistics(!eventView->showExtendedStatistics());
}
}
IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp,
RunConfiguration *runConfiguration)
{
QmlProfilerEngine *engine = new QmlProfilerEngine(this, sp, runConfiguration);
d->m_connectMode = QmlProfilerToolPrivate::TcpConnection;
engine->registerProfilerStateManager(d->m_profilerState);
bool isTcpConnection = true;
if (runConfiguration) {
// Check minimum Qt Version. We cannot really be sure what the Qt version
@@ -324,16 +255,15 @@ IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp
runConfiguration->target()->activeDeployConfiguration())) {
if (deployConfig->communicationChannel()
== Qt4ProjectManager::S60DeployConfiguration::CommunicationCodaSerialConnection) {
d->m_connectMode = QmlProfilerToolPrivate::OstConnection;
d->m_ostDevice = deployConfig->serialPortName();
d->m_profilerConnections->setOstConnection(deployConfig->serialPortName());
isTcpConnection = false;
}
}
}
// FIXME: Check that there's something sensible in sp.connParams
if (d->m_connectMode == QmlProfilerToolPrivate::TcpConnection) {
d->m_tcpHost = sp.connParams.host;
d->m_tcpPort = sp.connParams.port;
if (isTcpConnection) {
d->m_profilerConnections->setTcpConnection(sp.connParams.host, sp.connParams.port);
}
d->m_runConfiguration = runConfiguration;
@@ -364,20 +294,9 @@ IAnalyzerEngine *QmlProfilerTool::createEngine(const AnalyzerStartParameters &sp
d->m_projectFinder.setProjectFiles(sourceFiles);
d->m_projectFinder.setSysroot(sp.sysroot);
connect(engine, SIGNAL(processRunning(quint16)), this, SLOT(connectClient(quint16)));
connect(engine, SIGNAL(finished()), this, SLOT(disconnectClient()));
connect(engine, SIGNAL(finished()), this, SLOT(updateTimers()));
connect(engine, SIGNAL(stopRecording()), this, SLOT(stopRecording()));
connect(engine, SIGNAL(recordingChanged(bool)), this, SLOT(setRecording(bool)));
connect(engine, SIGNAL(timeUpdate()), this, SLOT(updateTimers()));
connect(d->m_traceWindow, SIGNAL(viewUpdated()), engine, SLOT(dataReceived()));
connect(this, SIGNAL(connectionFailed()), engine, SLOT(finishProcess()));
connect(this, SIGNAL(fetchingData(bool)), engine, SLOT(setFetchingData(bool)));
connect(engine, SIGNAL(starting(const Analyzer::IAnalyzerEngine*)), this, SLOT(setAppIsRunning()));
connect(engine, SIGNAL(finished()), this, SLOT(setAppIsStopped()));
connect(this, SIGNAL(cancelRun()), engine, SLOT(finishProcess()));
connect(engine, SIGNAL(applicationDied()), d->m_traceWindow, SLOT(applicationDied()));
emit fetchingData(d->m_recordButton->isChecked());
connect(engine, SIGNAL(processRunning(quint16)), d->m_profilerConnections, SLOT(connectClient(quint16)));
connect(engine, SIGNAL(finished()), d->m_profilerConnections, SLOT(disconnectClient()));
connect(d->m_profilerConnections, SIGNAL(connectionFailed()), engine, SLOT(cancelProcess()));
return engine;
}
@@ -444,53 +363,15 @@ AnalyzerStartParameters QmlProfilerTool::createStartParameters(RunConfiguration
QWidget *QmlProfilerTool::createWidgets()
{
QTC_ASSERT(!d->m_traceWindow, return 0);
QTC_ASSERT(!d->m_viewContainer, return 0);
//
// DockWidgets
//
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
d->m_traceWindow = new TraceWindow(mw);
d->m_traceWindow->reset(d->m_client);
connect(d->m_traceWindow, SIGNAL(clearViewsFromTool()), this, SLOT(clearDisplay()));
connect(d->m_traceWindow, SIGNAL(gotoSourceLocation(QString,int,int)),this, SLOT(gotoSourceLocation(QString,int,int)));
connect(d->m_traceWindow, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(d->m_traceWindow->getEventList(), SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
connect(d->m_traceWindow->getEventList(), SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
connect(d->m_traceWindow, SIGNAL(profilerStateChanged(bool,bool)), this, SLOT(profilerStateChanged(bool,bool)));
connect(d->m_traceWindow, SIGNAL(recordingChanged(bool)), this, SLOT(setRecording(bool)));
d->m_eventsView = new QmlProfilerEventsWidget(d->m_traceWindow->getEventList(), mw);
connect(d->m_eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this, SLOT(gotoSourceLocation(QString,int,int)));
connect(d->m_eventsView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(d->m_eventsView, SIGNAL(showEventInTimeline(int)), d->m_traceWindow, SLOT(selectNextEvent(int)));
connect(d->m_traceWindow, SIGNAL(selectedEventIdChanged(int)), d->m_eventsView, SLOT(updateSelectedEvent(int)));
d->m_v8profilerView = new QmlProfilerEventsWidget(d->m_traceWindow->getEventList(), mw);
d->m_v8profilerView->switchToV8View();
connect(d->m_v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)), this, SLOT(gotoSourceLocation(QString,int,int)));
connect(d->m_v8profilerView, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint)));
connect(d->m_v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)), d->m_eventsView, SLOT(selectBySourceLocation(QString,int,int)));
connect(d->m_eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), d->m_v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
(this, tr("Events"), d->m_eventsView, Qt::BottomDockWidgetArea);
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
(this, tr("Timeline"), d->m_traceWindow, Qt::BottomDockWidgetArea);
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
(this, tr("JavaScript"), d->m_v8profilerView, Qt::BottomDockWidgetArea);
eventsDock->show();
timelineDock->show();
v8profilerDock->show();
mw->splitDockWidget(mw->toolBarDockWidget(), eventsDock, Qt::Vertical);
mw->tabifyDockWidget(eventsDock, timelineDock);
mw->tabifyDockWidget(timelineDock, v8profilerDock);
d->m_viewContainer = new QmlProfilerViewManager(this,
this,
d->m_profilerDataModel,
d->m_profilerState);
connect(d->m_viewContainer, SIGNAL(gotoSourceLocation(QString,int,int)),
this, SLOT(gotoSourceLocation(QString,int,int)));
//
// Toolbar
@@ -507,118 +388,53 @@ QWidget *QmlProfilerTool::createWidgets()
connect(d->m_recordButton,SIGNAL(clicked(bool)), this, SLOT(recordingButtonChanged(bool)));
d->m_recordButton->setChecked(true);
setRecording(d->m_recordingEnabled);
setRecording(d->m_profilerState->clientRecording());
layout->addWidget(d->m_recordButton);
d->m_clearButton = new QToolButton(toolbarWidget);
d->m_clearButton->setIcon(QIcon(QLatin1String(":/qmlprofiler/clean_pane_small.png")));
d->m_clearButton->setToolTip(tr("Discard data"));
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearDisplay()));
connect(d->m_clearButton,SIGNAL(clicked()), this, SLOT(clearData()));
layout->addWidget(d->m_clearButton);
QLabel *timeLabel = new QLabel();
QPalette palette = timeLabel->palette();
d->m_timeLabel = new QLabel();
QPalette palette = d->m_timeLabel->palette();
palette.setColor(QPalette::WindowText, Qt::white);
timeLabel->setPalette(palette);
timeLabel->setIndent(10);
connect(d->m_traceWindow, SIGNAL(viewUpdated()), this, SLOT(updateTimers()));
connect(this, SIGNAL(setTimeLabel(QString)), timeLabel, SLOT(setText(QString)));
updateTimers();
layout->addWidget(timeLabel);
d->m_timeLabel->setPalette(palette);
d->m_timeLabel->setIndent(10);
updateTimeDisplay();
layout->addWidget(d->m_timeLabel);
toolbarWidget->setLayout(layout);
return toolbarWidget;
}
void QmlProfilerTool::connectClient(quint16 port)
{
if (d->m_client)
delete d->m_client;
d->m_client = new QDeclarativeDebugConnection;
d->m_traceWindow->reset(d->m_client);
connect(d->m_client, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this, SLOT(connectionStateChanged()));
d->m_connectionTimer.start();
d->m_appTimer.start();
d->m_tcpPort = port;
}
void QmlProfilerTool::connectToClient()
{
if (!d->m_client || d->m_client->state() != QAbstractSocket::UnconnectedState)
return;
if (d->m_connectMode == QmlProfilerToolPrivate::TcpConnection) {
logStatus(QString("QML Profiler: Connecting to %1:%2...").arg(d->m_tcpHost, QString::number(d->m_tcpPort)));
d->m_client->connectToHost(d->m_tcpHost, d->m_tcpPort);
} else {
logStatus(QString("QML Profiler: Connecting to %1...").arg(d->m_tcpHost));
d->m_client->connectToOst(d->m_ostDevice);
}
}
void QmlProfilerTool::disconnectClient()
{
// this might be actually be called indirectly by QDDConnectionPrivate::readyRead(), therefore allow
// method to complete before deleting object
if (d->m_client) {
d->m_client->deleteLater();
d->m_client = 0;
}
}
void QmlProfilerTool::startRecording()
{
if (d->m_client && d->m_client->isConnected()) {
clearDisplay();
d->m_traceWindow->setRecording(true);
}
emit fetchingData(true);
}
void QmlProfilerTool::stopRecording()
{
d->m_traceWindow->setRecording(false);
emit fetchingData(false);
// manage early stop
if (d->m_client && !d->m_client->isConnected() && d->m_appIsRunning)
emit cancelRun();
}
void QmlProfilerTool::recordingButtonChanged(bool recording)
{
if (recording)
startRecording();
else
stopRecording();
setRecording(recording);
d->m_profilerState->setClientRecording(recording);
}
void QmlProfilerTool::setRecording(bool recording)
{
// update record button
d->m_recordingEnabled = recording;
// update display
d->m_recordButton->setToolTip( recording ? tr("Disable profiling") : tr("Enable profiling"));
d->m_recordButton->setIcon(QIcon(recording ? QLatin1String(":/qmlprofiler/recordOn.png") :
QLatin1String(":/qmlprofiler/recordOff.png")));
d->m_recordButton->setChecked(recording);
updateTimers();
}
void QmlProfilerTool::setAppIsRunning()
{
d->m_appIsRunning = true;
updateTimers();
}
void QmlProfilerTool::setAppIsStopped()
{
d->m_appIsRunning = false;
updateTimers();
// manage timer
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
if (recording) {
d->m_recordingTimer.start();
d->m_recordingElapsedTime.start();
} else {
d->m_recordingTimer.stop();
}
}
}
void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber)
@@ -643,33 +459,30 @@ void QmlProfilerTool::gotoSourceLocation(const QString &fileUrl, int lineNumber,
}
}
inline QString stringifyTime(double seconds)
void QmlProfilerTool::updateTimeDisplay()
{
double seconds = 0;
if (d->m_profilerState->serverRecording() &&
d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
seconds = d->m_recordingElapsedTime.elapsed() / 1000.0;
} else if (d->m_profilerDataModel->currentState() != QmlProfilerDataModel::Empty ) {
seconds = (d->m_profilerDataModel->traceEndTime() - d->m_profilerDataModel->traceStartTime()) / 1.0e9;
}
QString timeString = QString::number(seconds,'f',1);
return QmlProfilerTool::tr("%1 s").arg(timeString, 6);
QString profilerTimeStr = QmlProfilerTool::tr("%1 s").arg(timeString, 6);
d->m_timeLabel->setText(tr("Elapsed: %1").arg(profilerTimeStr));
}
void QmlProfilerTool::updateTimers()
void QmlProfilerTool::clearData()
{
// prof time
QString profilerTimeStr = stringifyTime(d->m_traceWindow->profiledTime());
emit setTimeLabel(tr("Elapsed: %1").arg(profilerTimeStr));
}
void QmlProfilerTool::profilerStateChanged(bool qmlActive, bool v8active)
{
d->m_v8Active = v8active;
d->m_qmlActive = qmlActive;
updateTimers();
d->m_profilerDataModel->clear();
}
void QmlProfilerTool::clearDisplay()
{
d->m_appRunningTime = 0;
d->m_traceWindow->clearDisplay();
d->m_eventsView->clear();
d->m_v8profilerView->clear();
updateTimers();
d->m_profilerConnections->clearBufferedData();
d->m_viewContainer->clear();
updateTimeDisplay();
}
static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
@@ -718,84 +531,6 @@ static void startRemoteTool(IAnalyzerTool *tool, StartMode mode)
ProjectExplorerPlugin::instance()->startRunControl(rc, tool->runMode());
}
void QmlProfilerTool::tryToConnect()
{
++d->m_connectionAttempts;
if (d->m_client && d->m_client->isConnected()) {
d->m_connectionTimer.stop();
d->m_connectionAttempts = 0;
} else if (d->m_connectionAttempts == 50) {
d->m_connectionTimer.stop();
d->m_connectionAttempts = 0;
QMessageBox *infoBox = new QMessageBox(Core::ICore::mainWindow());
infoBox->setIcon(QMessageBox::Critical);
infoBox->setWindowTitle(tr("Qt Creator"));
infoBox->setText(tr("Could not connect to the in-process QML profiler.\n"
"Do you want to retry?"));
infoBox->setStandardButtons(QMessageBox::Retry | QMessageBox::Cancel | QMessageBox::Help);
infoBox->setDefaultButton(QMessageBox::Retry);
infoBox->setModal(true);
connect(infoBox, SIGNAL(finished(int)),
this, SLOT(retryMessageBoxFinished(int)));
infoBox->show();
} else {
connectToClient();
}
}
void QmlProfilerTool::connectionStateChanged()
{
if (!d->m_client)
return;
switch (d->m_client->state()) {
case QAbstractSocket::UnconnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: disconnected");
break;
}
case QAbstractSocket::HostLookupState:
break;
case QAbstractSocket::ConnectingState: {
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: Connecting to debug server ...");
break;
}
case QAbstractSocket::ConnectedState:
{
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: connected and running");
updateRecordingState();
break;
}
case QAbstractSocket::ClosingState:
if (QmlProfilerPlugin::debugOutput)
qWarning("QML Profiler: closing ...");
break;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
break;
}
}
void QmlProfilerTool::updateRecordingState()
{
if (d->m_client->isConnected()) {
d->m_traceWindow->setRecording(d->m_recordingEnabled);
} else {
d->m_traceWindow->setRecording(false);
}
if (d->m_traceWindow->isRecording())
clearDisplay();
updateTimers();
}
void QmlProfilerTool::startTool(StartMode mode)
{
using namespace ProjectExplorer;
@@ -821,14 +556,25 @@ void QmlProfilerTool::logStatus(const QString &msg)
void QmlProfilerTool::logError(const QString &msg)
{
// TODO: Rather show errors in the application ouput
MessageManager *messageManager = MessageManager::instance();
messageManager->printToOutputPane(msg, true);
}
void QmlProfilerTool::showErrorDialog(const QString &error)
{
QMessageBox *errorDialog = new QMessageBox(Core::ICore::mainWindow());
errorDialog->setIcon(QMessageBox::Warning);
errorDialog->setWindowTitle(tr("QML Profiler"));
errorDialog->setText(error);
errorDialog->setStandardButtons(QMessageBox::Ok);
errorDialog->setDefaultButton(QMessageBox::Ok);
errorDialog->setModal(false);
errorDialog->show();
}
void QmlProfilerTool::showSaveOption()
{
d->m_saveQmlTrace->setEnabled(d->m_traceWindow->getEventList()->count());
d->m_saveQmlTrace->setEnabled(!d->m_profilerDataModel->isEmpty());
}
void QmlProfilerTool::showSaveDialog()
@@ -837,7 +583,7 @@ void QmlProfilerTool::showSaveDialog()
if (!filename.isEmpty()) {
if (!filename.endsWith(QLatin1String(TraceFileExtension)))
filename += QLatin1String(TraceFileExtension);
d->m_traceWindow->getEventList()->save(filename);
d->m_profilerDataModel->save(filename);
}
}
@@ -853,53 +599,98 @@ void QmlProfilerTool::showLoadDialog()
if (!filename.isEmpty()) {
// delayed load (prevent graphical artifacts due to long load time)
d->m_traceWindow->getEventList()->setFilename(filename);
QTimer::singleShot(100, d->m_traceWindow->getEventList(), SLOT(load()));
d->m_profilerDataModel->setFilename(filename);
QTimer::singleShot(100, d->m_profilerDataModel, SLOT(load()));
}
}
void QmlProfilerTool::showErrorDialog(const QString &error)
void QmlProfilerTool::profilerDataModelStateChanged()
{
QMessageBox *errorDialog = new QMessageBox(Core::ICore::mainWindow());
errorDialog->setIcon(QMessageBox::Warning);
errorDialog->setWindowTitle(tr("QML Profiler"));
errorDialog->setText(error);
errorDialog->setStandardButtons(QMessageBox::Ok);
errorDialog->setDefaultButton(QMessageBox::Ok);
errorDialog->setModal(false);
errorDialog->show();
}
void QmlProfilerTool::retryMessageBoxFinished(int result)
{
switch (result) {
case QMessageBox::Retry: {
d->m_connectionAttempts = 0;
d->m_connectionTimer.start();
switch (d->m_profilerDataModel->currentState()) {
case QmlProfilerDataModel::Empty :
clearDisplay();
break;
}
case QMessageBox::Help: {
HelpManager *helpManager = HelpManager::instance();
helpManager->handleHelpRequest("qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html");
// fall through
}
default: {
if (d->m_client) {
logStatus("QML Profiler: Failed to connect! " + d->m_client->errorString());
} else {
logStatus("QML Profiler: Failed to connect!");
}
emit connectionFailed();
case QmlProfilerDataModel::AcquiringData :
case QmlProfilerDataModel::ProcessingData :
// nothing to be done for these two
break;
}
}
}
void QmlProfilerTool::eventListStateChanged()
{
if (d->m_traceWindow->getEventList()->currentState() == QmlProfilerEventList::Done) {
case QmlProfilerDataModel::Done :
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppStopRequested)
d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppReadyToStop);
showSaveOption();
updateTimers();
updateTimeDisplay();
break;
default:
break;
}
}
QList <QAction *> QmlProfilerTool::profilerContextMenuActions() const
{
QList <QAction *> commonActions;
commonActions << d->m_loadQmlTrace << d->m_saveQmlTrace;
return commonActions;
}
void QmlProfilerTool::showNonmodalWarning(const QString &warningMsg)
{
QMessageBox *noExecWarning = new QMessageBox(Core::ICore::mainWindow());
noExecWarning->setIcon(QMessageBox::Warning);
noExecWarning->setWindowTitle(tr("QML Profiler"));
noExecWarning->setText(warningMsg);
noExecWarning->setStandardButtons(QMessageBox::Ok);
noExecWarning->setDefaultButton(QMessageBox::Ok);
noExecWarning->setModal(false);
noExecWarning->show();
}
QMessageBox *QmlProfilerTool::requestMessageBox()
{
return new QMessageBox(Core::ICore::mainWindow());
}
void QmlProfilerTool::handleHelpRequest(const QString &link)
{
HelpManager *helpManager = HelpManager::instance();
helpManager->handleHelpRequest(link);
}
void QmlProfilerTool::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppKilled : {
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData) {
showNonmodalWarning(tr("Application finished before loading profiled data.\n Please use the stop button instead."));
}
break;
}
case QmlProfilerStateManager::Idle :
// when the app finishes, set recording display to client status
setRecording(d->m_profilerState->clientRecording());
break;
default:
// no special action needed for other states
break;
}
}
void QmlProfilerTool::clientRecordingChanged()
{
// if application is running, display server record changes
// if application is stopped, display client record changes
if (d->m_profilerState->currentState() != QmlProfilerStateManager::AppRunning) {
setRecording(d->m_profilerState->clientRecording());
}
}
void QmlProfilerTool::serverRecordingChanged()
{
if (d->m_profilerState->currentState() == QmlProfilerStateManager::AppRunning) {
setRecording(d->m_profilerState->serverRecording());
// clear the old data each time we start a new profiling session
if (d->m_profilerState->serverRecording()) {
clearData();
}
}
}

View File

@@ -36,13 +36,11 @@
#include <analyzerbase/ianalyzertool.h>
#include <analyzerbase/ianalyzerengine.h>
#include <QPoint>
class QMessageBox;
namespace QmlProfiler {
namespace Internal {
#define TraceFileExtension ".qtd"
class QmlProfilerTool : public Analyzer::IAnalyzerTool
{
Q_OBJECT
@@ -72,49 +70,37 @@ public:
QWidget *createWidgets();
void startTool(Analyzer::StartMode mode);
public slots:
void connectClient(quint16 port);
void disconnectClient();
QList <QAction *> profilerContextMenuActions() const;
// display dialogs / log output
static QMessageBox *requestMessageBox();
static void handleHelpRequest(const QString &link);
static void logStatus(const QString &msg);
static void logError(const QString &msg);
static void showNonmodalWarning(const QString &warningMsg);
public slots:
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
void startRecording();
void stopRecording();
void recordingButtonChanged(bool recording);
void setRecording(bool recording);
void setAppIsRunning();
void setAppIsStopped();
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columnNumber);
void updateTimers();
void profilerStateChanged(bool qmlActive, bool v8active);
void clearDisplay();
void showContextMenu(const QPoint &position);
signals:
void setTimeLabel(const QString &);
void setStatusLabel(const QString &);
void fetchingData(bool);
void connectionFailed();
void cancelRun();
private slots:
void tryToConnect();
void connectionStateChanged();
void clearData();
void showErrorDialog(const QString &error);
void profilerDataModelStateChanged();
void updateTimeDisplay();
void showSaveOption();
void showSaveDialog();
void showLoadDialog();
void showErrorDialog(const QString &error);
void retryMessageBoxFinished(int result);
void eventListStateChanged();
private:
void connectToClient();
void updateRecordingState();
void ensureWidgets();
void logStatus(const QString &msg);
void logError(const QString &msg);
void clearDisplay();
class QmlProfilerToolPrivate;
QmlProfilerToolPrivate *d;

View File

@@ -0,0 +1,601 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmlprofilertraceview.h"
#include "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilerdatamodel.h"
// Needed for the load&save actions in the context menu
#include <analyzerbase/ianalyzertool.h>
// Comunication with the other views (limit events to range)
#include "qmlprofilerviewmanager.h"
#include <utils/styledbar.h>
#include <QDeclarativeContext>
#include <QToolButton>
#include <QEvent>
#include <QVBoxLayout>
#include <QGraphicsObject>
#include <QScrollBar>
#include <QSlider>
#include <QMenu>
#include <math.h>
using namespace QmlJsDebugClient;
namespace QmlProfiler {
namespace Internal {
const int sliderTicks = 10000;
const qreal sliderExp = 3;
/////////////////////////////////////////////////////////
bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Wheel) {
QWheelEvent *ev = static_cast<QWheelEvent *>(event);
if (ev->modifiers() & Qt::ControlModifier) {
emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta());
return true;
}
}
return QObject::eventFilter(obj, event);
}
/////////////////////////////////////////////////////////
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
{
if (m_startTime != startTime || m_endTime != endTime) {
m_startTime = startTime;
m_endTime = endTime;
emit rangeChanged();
}
}
/////////////////////////////////////////////////////////
ScrollableDeclarativeView::ScrollableDeclarativeView(QWidget *parent)
: QDeclarativeView(parent)
{
}
ScrollableDeclarativeView::~ScrollableDeclarativeView()
{
}
void ScrollableDeclarativeView::scrollContentsBy(int dx, int dy)
{
// special workaround to track the scrollbar
if (rootObject()) {
int scrollY = rootObject()->property("scrollY").toInt();
rootObject()->setProperty("scrollY", QVariant(scrollY - dy));
}
QDeclarativeView::scrollContentsBy(dx,dy);
}
/////////////////////////////////////////////////////////
class QmlProfilerTraceView::QmlProfilerTraceViewPrivate
{
public:
QmlProfilerTraceViewPrivate(QmlProfilerTraceView *qq) : q(qq) {}
QmlProfilerTraceView *q;
QmlProfilerStateManager *m_profilerState;
Analyzer::IAnalyzerTool *m_profilerTool;
QmlProfilerViewManager *m_viewContainer;
QSize m_sizeHint;
ScrollableDeclarativeView *m_mainView;
QDeclarativeView *m_timebar;
QDeclarativeView *m_overview;
QmlProfilerDataModel *m_profilerDataModel;
ZoomControl *m_zoomControl;
QToolButton *m_buttonRange;
QToolButton *m_buttonLock;
QWidget *m_zoomToolbar;
int m_currentZoomLevel;
};
QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState)
: QWidget(parent), d(new QmlProfilerTraceViewPrivate(this))
{
setObjectName("QML Profiler");
d->m_zoomControl = new ZoomControl(this);
connect(d->m_zoomControl, SIGNAL(rangeChanged()), this, SLOT(updateRange()));
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0, 0, 0, 0);
groupLayout->setSpacing(0);
d->m_mainView = new ScrollableDeclarativeView(this);
d->m_mainView->setResizeMode(QDeclarativeView::SizeViewToRootObject);
d->m_mainView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
d->m_mainView->setBackgroundBrush(QBrush(Qt::white));
d->m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
d->m_mainView->setFocus();
MouseWheelResizer *resizer = new MouseWheelResizer(this);
connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int)));
d->m_mainView->viewport()->installEventFilter(resizer);
QHBoxLayout *toolsLayout = new QHBoxLayout;
d->m_timebar = new QDeclarativeView(this);
d->m_timebar->setResizeMode(QDeclarativeView::SizeRootObjectToView);
d->m_timebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
d->m_timebar->setFixedHeight(24);
d->m_overview = new QDeclarativeView(this);
d->m_overview->setResizeMode(QDeclarativeView::SizeRootObjectToView);
d->m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
d->m_overview->setMaximumHeight(50);
d->m_zoomToolbar = createZoomToolbar();
d->m_zoomToolbar->move(0, d->m_timebar->height());
d->m_zoomToolbar->setVisible(false);
toolsLayout->addWidget(createToolbar());
toolsLayout->addWidget(d->m_timebar);
emit enableToolbar(false);
groupLayout->addLayout(toolsLayout);
groupLayout->addWidget(d->m_mainView);
groupLayout->addWidget(d->m_overview);
setLayout(groupLayout);
d->m_profilerTool = profilerTool;
d->m_viewContainer = container;
d->m_profilerDataModel = model;
connect(d->m_profilerDataModel, SIGNAL(stateChanged()),
this, SLOT(profilerDataModelStateChanged()));
d->m_mainView->rootContext()->setContextProperty("qmlProfilerDataModel",
d->m_profilerDataModel);
d->m_overview->rootContext()->setContextProperty("qmlProfilerDataModel",
d->m_profilerDataModel);
d->m_profilerState = profilerState;
connect(d->m_profilerState, SIGNAL(stateChanged()),
this, SLOT(profilerStateChanged()));
connect(d->m_profilerState, SIGNAL(clientRecordingChanged()),
this, SLOT(clientRecordingChanged()));
connect(d->m_profilerState, SIGNAL(serverRecordingChanged()),
this, SLOT(serverRecordingChanged()));
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
setMinimumHeight(170);
d->m_currentZoomLevel = 0;
}
QmlProfilerTraceView::~QmlProfilerTraceView()
{
delete d;
}
/////////////////////////////////////////////////////////
// Initialize widgets
void QmlProfilerTraceView::reset()
{
d->m_mainView->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
d->m_timebar->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
d->m_overview->rootContext()->setContextProperty("zoomControl", d->m_zoomControl);
d->m_timebar->setSource(QUrl("qrc:/qmlprofiler/TimeDisplay.qml"));
d->m_overview->setSource(QUrl("qrc:/qmlprofiler/Overview.qml"));
d->m_mainView->setSource(QUrl("qrc:/qmlprofiler/MainView.qml"));
d->m_mainView->rootObject()->setProperty("width", QVariant(width()));
d->m_mainView->rootObject()->setProperty("candidateHeight", QVariant(height() - d->m_timebar->height() - d->m_overview->height()));
connect(d->m_mainView->rootObject(), SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
connect(d->m_mainView->rootObject(), SIGNAL(updateRangeButton()), this, SLOT(updateRangeButton()));
connect(d->m_mainView->rootObject(), SIGNAL(updateLockButton()), this, SLOT(updateLockButton()));
connect(this, SIGNAL(jumpToPrev()), d->m_mainView->rootObject(), SLOT(prevEvent()));
connect(this, SIGNAL(jumpToNext()), d->m_mainView->rootObject(), SLOT(nextEvent()));
connect(d->m_mainView->rootObject(), SIGNAL(selectedEventChanged(int)), this, SIGNAL(selectedEventChanged(int)));
connect(d->m_mainView->rootObject(), SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString)));
connect(d->m_mainView->rootObject(), SIGNAL(updateVerticalScroll(int)), this, SLOT(updateVerticalScroll(int)));
}
QWidget *QmlProfilerTraceView::createToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QToolButton *buttonPrev= new QToolButton;
buttonPrev->setIcon(QIcon(":/qmlprofiler/ico_prev.png"));
buttonPrev->setToolTip(tr("Jump to previous event"));
connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev()));
connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool)));
QToolButton *buttonNext= new QToolButton;
buttonNext->setIcon(QIcon(":/qmlprofiler/ico_next.png"));
buttonNext->setToolTip(tr("Jump to next event"));
connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext()));
connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool)));
QToolButton *buttonZoomControls = new QToolButton;
buttonZoomControls->setIcon(QIcon(":/qmlprofiler/ico_zoom.png"));
buttonZoomControls->setToolTip(tr("Show zoom slider"));
buttonZoomControls->setCheckable(true);
buttonZoomControls->setChecked(false);
connect(buttonZoomControls, SIGNAL(toggled(bool)), d->m_zoomToolbar, SLOT(setVisible(bool)));
connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool)));
d->m_buttonRange = new QToolButton;
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
d->m_buttonRange->setToolTip(tr("Select range"));
d->m_buttonRange->setCheckable(true);
d->m_buttonRange->setChecked(false);
connect(d->m_buttonRange, SIGNAL(clicked(bool)), this, SLOT(toggleRangeMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonRange, SLOT(setEnabled(bool)));
connect(this, SIGNAL(rangeModeChanged(bool)), d->m_buttonRange, SLOT(setChecked(bool)));
d->m_buttonLock = new QToolButton;
d->m_buttonLock->setIcon(QIcon(":/qmlprofiler/ico_selectionmode.png"));
d->m_buttonLock->setToolTip(tr("View event information on mouseover"));
d->m_buttonLock->setCheckable(true);
d->m_buttonLock->setChecked(false);
connect(d->m_buttonLock, SIGNAL(clicked(bool)), this, SLOT(toggleLockMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), d->m_buttonLock, SLOT(setEnabled(bool)));
connect(this, SIGNAL(lockModeChanged(bool)), d->m_buttonLock, SLOT(setChecked(bool)));
toolBarLayout->addWidget(buttonPrev);
toolBarLayout->addWidget(buttonNext);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(buttonZoomControls);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(d->m_buttonRange);
toolBarLayout->addWidget(d->m_buttonLock);
return bar;
}
QWidget *QmlProfilerTraceView::createZoomToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QSlider *zoomSlider = new QSlider(Qt::Horizontal);
zoomSlider->setFocusPolicy(Qt::NoFocus);
zoomSlider->setRange(1, sliderTicks);
zoomSlider->setInvertedAppearance(true);
zoomSlider->setPageStep(sliderTicks/100);
connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool)));
connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int)));
zoomSlider->setStyleSheet("\
QSlider:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\
border: 1px #313131;\
height: 20px;\
margin: 0px 0px 0px 0px;\
}\
QSlider::add-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
QSlider::sub-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
");
toolBarLayout->addWidget(zoomSlider);
return bar;
}
/////////////////////////////////////////////////////////
bool QmlProfilerTraceView::hasValidSelection() const
{
if (d->m_mainView->rootObject()) {
return d->m_mainView->rootObject()->property("selectionRangeReady").toBool();
}
return false;
}
qint64 QmlProfilerTraceView::selectionStart() const
{
if (d->m_mainView->rootObject()) {
return d->m_mainView->rootObject()->property("selectionRangeStart").toLongLong();
}
return 0;
}
qint64 QmlProfilerTraceView::selectionEnd() const
{
if (d->m_mainView->rootObject()) {
return d->m_mainView->rootObject()->property("selectionRangeEnd").toLongLong();
}
return 0;
}
void QmlProfilerTraceView::clearDisplay()
{
d->m_zoomControl->setRange(0,0);
updateVerticalScroll(0);
d->m_mainView->rootObject()->setProperty("scrollY", QVariant(0));
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "clearAll");
QMetaObject::invokeMethod(d->m_overview->rootObject(), "clearDisplay");
}
void QmlProfilerTraceView::selectNextEventWithId(int eventId)
{
if (d->m_mainView->rootObject())
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "selectNextWithId",
Q_ARG(QVariant,QVariant(eventId)));
}
/////////////////////////////////////////////////////////
// Goto source location
void QmlProfilerTraceView::updateCursorPosition()
{
emit gotoSourceLocation(d->m_mainView->rootObject()->property("fileName").toString(),
d->m_mainView->rootObject()->property("lineNumber").toInt(),
d->m_mainView->rootObject()->property("columnNumber").toInt());
}
/////////////////////////////////////////////////////////
// Toolbar buttons
void QmlProfilerTraceView::toggleRangeMode(bool active)
{
bool rangeMode = d->m_mainView->rootObject()->property("selectionRangeMode").toBool();
if (active != rangeMode) {
if (active)
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
else
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
d->m_mainView->rootObject()->setProperty("selectionRangeMode", QVariant(active));
}
}
void QmlProfilerTraceView::updateRangeButton()
{
bool rangeMode = d->m_mainView->rootObject()->property("selectionRangeMode").toBool();
if (rangeMode)
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
else
d->m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
emit rangeModeChanged(rangeMode);
}
void QmlProfilerTraceView::toggleLockMode(bool active)
{
bool lockMode = !d->m_mainView->rootObject()->property("selectionLocked").toBool();
if (active != lockMode) {
d->m_mainView->rootObject()->setProperty("selectionLocked", QVariant(!active));
d->m_mainView->rootObject()->setProperty("selectedItem", QVariant(-1));
}
}
void QmlProfilerTraceView::updateLockButton()
{
bool lockMode = !d->m_mainView->rootObject()->property("selectionLocked").toBool();
emit lockModeChanged(lockMode);
}
////////////////////////////////////////////////////////
// Zoom control
void QmlProfilerTraceView::setZoomLevel(int zoomLevel)
{
if (d->m_currentZoomLevel != zoomLevel && d->m_mainView->rootObject()) {
QVariant newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp);
d->m_currentZoomLevel = zoomLevel;
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "updateWindowLength", Q_ARG(QVariant, newFactor));
}
}
void QmlProfilerTraceView::updateRange()
{
if (!d->m_profilerDataModel)
return;
qreal duration = d->m_zoomControl->endTime() - d->m_zoomControl->startTime();
if (duration <= 0)
return;
if (d->m_profilerDataModel->traceDuration() <= 0)
return;
int newLevel = pow(duration / d->m_profilerDataModel->traceDuration(), 1/sliderExp) * sliderTicks;
if (d->m_currentZoomLevel != newLevel) {
d->m_currentZoomLevel = newLevel;
emit zoomLevelChanged(newLevel);
}
}
void QmlProfilerTraceView::mouseWheelMoved(int mouseX, int mouseY, int wheelDelta)
{
Q_UNUSED(mouseY);
if (d->m_mainView->rootObject()) {
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "wheelZoom",
Q_ARG(QVariant, QVariant(mouseX)),
Q_ARG(QVariant, QVariant(wheelDelta)));
}
}
////////////////////////////////////////////////////////
void QmlProfilerTraceView::updateToolTip(const QString &text)
{
setToolTip(text);
}
void QmlProfilerTraceView::updateVerticalScroll(int newPosition)
{
d->m_mainView->verticalScrollBar()->setValue(newPosition);
}
void QmlProfilerTraceView::resizeEvent(QResizeEvent *event)
{
if (d->m_mainView->rootObject()) {
d->m_mainView->rootObject()->setProperty("width", QVariant(event->size().width()));
int newHeight = event->size().height() - d->m_timebar->height() - d->m_overview->height();
d->m_mainView->rootObject()->setProperty("candidateHeight", QVariant(newHeight));
}
}
////////////////////////////////////////////////////////////////
// Context menu
void QmlProfilerTraceView::contextMenuEvent(QContextMenuEvent *ev)
{
QMenu menu;
QAction *viewAllAction = 0;
QAction *getLocalStatsAction = 0;
QAction *getGlobalStatsAction = 0;
QmlProfilerTool *profilerTool = qobject_cast<QmlProfilerTool *>(d->m_profilerTool);
QPoint position = ev->globalPos();
if (profilerTool) {
QList <QAction *> commonActions = profilerTool->profilerContextMenuActions();
foreach (QAction *act, commonActions) {
menu.addAction(act);
}
}
menu.addSeparator();
getLocalStatsAction = menu.addAction(tr("Limit Events Pane to Current Range"));
if (!d->m_viewContainer->hasValidSelection())
getLocalStatsAction->setEnabled(false);
getGlobalStatsAction = menu.addAction(tr("Reset Events Pane"));
if (d->m_viewContainer->hasGlobalStats())
getGlobalStatsAction->setEnabled(false);
if (d->m_profilerDataModel->count() > 0) {
menu.addSeparator();
viewAllAction = menu.addAction(tr("Reset Zoom"));
}
QAction *selectedAction = menu.exec(position);
if (selectedAction) {
if (selectedAction == viewAllAction) {
d->m_zoomControl->setRange(
d->m_profilerDataModel->traceStartTime(),
d->m_profilerDataModel->traceEndTime());
}
if (selectedAction == getLocalStatsAction) {
d->m_viewContainer->getStatisticsInRange(
d->m_viewContainer->selectionStart(),
d->m_viewContainer->selectionEnd());
}
if (selectedAction == getGlobalStatsAction) {
d->m_viewContainer->getStatisticsInRange(
d->m_profilerDataModel->traceStartTime(),
d->m_profilerDataModel->traceEndTime());
}
}
}
/////////////////////////////////////////////////
// Tell QML the state of the profiler
void QmlProfilerTraceView::setRecording(bool recording)
{
if (d->m_mainView->rootObject())
d->m_mainView->rootObject()->setProperty("recordingEnabled", QVariant(recording));
}
void QmlProfilerTraceView::setAppKilled()
{
if (d->m_mainView->rootObject())
d->m_mainView->rootObject()->setProperty("appKilled",QVariant(true));
}
////////////////////////////////////////////////////////////////
// Profiler State
void QmlProfilerTraceView::profilerDataModelStateChanged()
{
switch (d->m_profilerDataModel->currentState()) {
case QmlProfilerDataModel::Empty :
emit enableToolbar(false);
break;
case QmlProfilerDataModel::AcquiringData :
// nothing to be done
break;
case QmlProfilerDataModel::ProcessingData :
// nothing to be done
break;
case QmlProfilerDataModel::Done :
emit enableToolbar(true);
break;
default:
break;
}
}
void QmlProfilerTraceView::profilerStateChanged()
{
switch (d->m_profilerState->currentState()) {
case QmlProfilerStateManager::AppKilled : {
if (d->m_profilerDataModel->currentState() == QmlProfilerDataModel::AcquiringData)
setAppKilled();
break;
}
default:
// no special action needed for other states
break;
}
}
void QmlProfilerTraceView::clientRecordingChanged()
{
// nothing yet
}
void QmlProfilerTraceView::serverRecordingChanged()
{
setRecording(d->m_profilerState->serverRecording());
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -30,24 +30,23 @@
**
**************************************************************************/
#ifndef TRACEWINDOW_H
#define TRACEWINDOW_H
#ifndef QMLPROFILERTRACEVIEW_H
#define QMLPROFILERTRACEVIEW_H
#include <qmljsdebugclient/qmlprofilertraceclient.h>
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include "qmlprofilerdetailsrewriter.h"
#include <qmljsdebugclient/qv8profilerclient.h>
#include <QPointer>
#include <QWidget>
#include <QToolButton>
#include <QEvent>
#include <QDeclarativeView>
namespace Analyzer {
class IAnalyzerTool;
}
namespace QmlProfiler {
namespace Internal {
class QmlProfilerStateManager;
class QmlProfilerViewManager;
class QmlProfilerDataModel;
// capture mouse wheel events
class MouseWheelResizer : public QObject {
Q_OBJECT
public:
@@ -87,117 +86,73 @@ protected:
void scrollContentsBy(int dx, int dy);
};
class TraceWindow : public QWidget
class QmlProfilerTraceView : public QWidget
{
Q_OBJECT
public:
TraceWindow(QWidget *parent = 0);
~TraceWindow();
explicit QmlProfilerTraceView(QWidget *parent, Analyzer::IAnalyzerTool *profilerTool, QmlProfilerViewManager *container, QmlProfilerDataModel *model, QmlProfilerStateManager *profilerState);
~QmlProfilerTraceView();
void reset(QmlJsDebugClient::QDeclarativeDebugConnection *conn);
QmlJsDebugClient::QmlProfilerEventList *getEventList() const;
ZoomControl *rangeTimes() const;
void setRecording(bool recording);
bool isRecording() const;
void viewAll();
void reset();
bool hasValidSelection() const;
qint64 selectionStart() const;
qint64 selectionEnd() const;
double profiledTime() const;
public slots:
void clearDisplay();
void selectNextEvent(int eventId);
void applicationDied();
void selectNextEventWithId(int eventId);
private slots:
void updateCursorPosition();
void updateTimer();
void updateToolbar();
void toggleRangeMode(bool);
void toggleLockMode(bool);
void updateRangeButton();
void toggleLockMode(bool);
void updateLockButton();
void setZoomLevel(int zoomLevel);
void updateRange();
void mouseWheelMoved(int x, int y, int delta);
void mouseWheelMoved(int mouseX, int mouseY, int wheelDelta);
void qmlComplete();
void v8Complete();
void updateProfilerState();
void updateToolTip(const QString &text);
void updateVerticalScroll(int newPosition);
void eventListStateChanged();
void manageTraceStart(qint64 traceStart);
void firstDataReceived();
void correctTimer();
void profilerDataModelStateChanged();
protected:
virtual void resizeEvent(QResizeEvent *event);
private slots:
void profilerStateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
signals:
void viewUpdated();
void profilerStateChanged(bool qmlActive, bool v8active);
void gotoSourceLocation(const QString &fileUrl, int lineNumber, int columNumber);
void range(int type, qint64 startTime, qint64 length, const QStringList &data, const QmlJsDebugClient::QmlEventLocation &location);
void v8range(int depth,const QString &function,const QString &filename,
int lineNumber, double totalTime, double selfTime);
void traceFinished(qint64);
void traceStarted(qint64);
void frameEvent(qint64, int, int);
void recordingChanged(bool);
void selectedEventChanged(int eventId);
void internalClearDisplay();
void clearViewsFromTool();
void jumpToPrev();
void jumpToNext();
void rangeModeChanged(bool);
void lockModeChanged(bool);
void enableToolbar(bool);
void zoomLevelChanged(int);
void updateViewZoom(QVariant zoomLevel);
void wheelZoom(QVariant wheelCenter, QVariant wheelDelta);
void globalZoom();
void contextMenuRequested(const QPoint& position);
void selectNextEventInDisplay(QVariant eventId);
void selectedEventIdChanged(int eventId);
private:
void contextMenuEvent(QContextMenuEvent *);
QWidget *createToolbar();
QWidget *createZoomToolbar();
void connectClientSignals();
void disconnectClientSignals();
protected:
virtual void resizeEvent(QResizeEvent *event);
void setRecording(bool recording);
void setAppKilled();
private:
QWeakPointer<QmlJsDebugClient::QmlProfilerTraceClient> m_plugin;
QWeakPointer<QmlJsDebugClient::QV8ProfilerClient> m_v8plugin;
QSize m_sizeHint;
ScrollableDeclarativeView *m_mainView;
QDeclarativeView *m_timebar;
QDeclarativeView *m_overview;
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
QmlProfilerDetailsRewriter *m_rewriter;
bool m_qmlDataReady;
bool m_v8DataReady;
double m_profiledTime;
QWeakPointer<ZoomControl> m_zoomControl;
QToolButton *m_buttonRange;
QToolButton *m_buttonLock;
QWidget *m_zoomToolbar;
int m_currentZoomLevel;
class QmlProfilerTraceViewPrivate;
QmlProfilerTraceViewPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // TRACEWINDOW_H
#endif // QMLPROFILERTRACEVIEW_H

View File

@@ -0,0 +1,172 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmlprofilerviewmanager.h"
#include "qmlprofilertraceview.h"
#include "qmlprofilereventview.h"
#include "qmlprofilertool.h"
#include "qmlprofilerstatemanager.h"
#include "qmlprofilerdatamodel.h"
#include <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <analyzerbase/analyzermanager.h>
#include <QDockWidget>
using namespace Analyzer;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerViewManager::QmlProfilerViewManagerPrivate {
public:
QmlProfilerViewManagerPrivate(QmlProfilerViewManager *qq) { Q_UNUSED(qq); }
QmlProfilerTraceView *traceView;
QmlProfilerEventsWidget *eventsView;
QmlProfilerEventsWidget *v8profilerView;
QmlProfilerStateManager *profilerState;
QmlProfilerDataModel *profilerDataModel;
QmlProfilerTool *profilerTool;
};
QmlProfilerViewManager::QmlProfilerViewManager(QObject *parent,
QmlProfilerTool *profilerTool,
QmlProfilerDataModel *model,
QmlProfilerStateManager *profilerState)
: QObject(parent), d(new QmlProfilerViewManagerPrivate(this))
{
setObjectName("QML Profiler View Manager");
d->traceView = 0;
d->eventsView = 0;
d->v8profilerView = 0;
d->profilerState = profilerState;
d->profilerDataModel = model;
d->profilerTool = profilerTool;
createViews();
}
QmlProfilerViewManager::~QmlProfilerViewManager()
{
delete d;
}
////////////////////////////////////////////////////////////
// Views
void QmlProfilerViewManager::createViews()
{
QTC_ASSERT(d->profilerDataModel, return);
QTC_ASSERT(d->profilerState, return);
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
d->traceView = new QmlProfilerTraceView(mw,
d->profilerTool,
this,
d->profilerDataModel,
d->profilerState);
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
this, SIGNAL(gotoSourceLocation(QString,int,int)));
d->traceView->reset();
d->eventsView = new QmlProfilerEventsWidget(mw, d->profilerTool, this, d->profilerDataModel);
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this,
SIGNAL(gotoSourceLocation(QString,int,int)));
connect(d->eventsView, SIGNAL(showEventInTimeline(int)), d->traceView,
SLOT(selectNextEventWithId(int)));
connect(d->traceView, SIGNAL(selectedEventChanged(int)), d->eventsView,
SLOT(updateSelectedEvent(int)));
d->v8profilerView = new QmlProfilerEventsWidget(mw, d->profilerTool,
this, d->profilerDataModel);
d->v8profilerView->switchToV8View();
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
this, SIGNAL(gotoSourceLocation(QString,int,int)));
connect(d->v8profilerView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)),
d->v8profilerView, SLOT(selectBySourceLocation(QString,int,int)));
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
(d->profilerTool, tr("Events"), d->eventsView, Qt::BottomDockWidgetArea);
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
(d->profilerTool, tr("Timeline"), d->traceView, Qt::BottomDockWidgetArea);
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
(d->profilerTool, tr("JavaScript"), d->v8profilerView, Qt::BottomDockWidgetArea);
eventsDock->show();
timelineDock->show();
v8profilerDock->show();
mw->splitDockWidget(mw->toolBarDockWidget(), eventsDock, Qt::Vertical);
mw->tabifyDockWidget(eventsDock, timelineDock);
mw->tabifyDockWidget(timelineDock, v8profilerDock);
}
bool QmlProfilerViewManager::hasValidSelection() const
{
return d->traceView->hasValidSelection();
}
qint64 QmlProfilerViewManager::selectionStart() const
{
return d->traceView->selectionStart();
}
qint64 QmlProfilerViewManager::selectionEnd() const
{
return d->traceView->selectionEnd();
}
bool QmlProfilerViewManager::hasGlobalStats() const
{
return d->eventsView->hasGlobalStats();
}
void QmlProfilerViewManager::getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd)
{
d->eventsView->getStatisticsInRange(rangeStart, rangeEnd);
}
void QmlProfilerViewManager::clear()
{
d->traceView->clearDisplay();
d->eventsView->clear();
d->v8profilerView->clear();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -30,26 +30,50 @@
**
**************************************************************************/
#include "qmlprofilerapplication.h"
#include "commandlistener.h"
#ifndef QMLPROFILERVIEWMANAGER_H
#define QMLPROFILERVIEWMANAGER_H
int main(int argc, char *argv[])
#include <QObject>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTool;
class QmlProfilerDataModel;
class QmlProfilerStateManager;
class QmlProfilerViewManager : public QObject
{
QmlProfilerApplication app(argc, argv);
Q_OBJECT
public:
explicit QmlProfilerViewManager(QObject *parent,
QmlProfilerTool *profilerTool,
QmlProfilerDataModel *model,
QmlProfilerStateManager *profilerState);
~QmlProfilerViewManager();
if (!app.parseArguments()) {
app.printUsage();
return 1;
}
void createViews();
CommandListener listener;
QObject::connect(&listener, SIGNAL(command(QString)), &app, SLOT(userCommand(QString)));
listener.start();
// used by the options "limit events to range"
bool hasValidSelection() const;
qint64 selectionStart() const;
qint64 selectionEnd() const;
bool hasGlobalStats() const;
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
int exitValue = app.exec();
// wait for listener to exit
listener.wait();
public slots:
void clear();
signals:
void gotoSourceLocation(QString,int,int);
private:
class QmlProfilerViewManagerPrivate;
QmlProfilerViewManagerPrivate *d;
};
return exitValue;
}
} // namespace Internal
} // namespace QmlProfiler
#endif // QMLPROFILERVIEWMANAGER_H

View File

@@ -0,0 +1,445 @@
#include "qv8profilerdatamodel.h"
#include "qmlprofilerdatamodel.h"
#include <QStringList>
using namespace QmlJsDebugClient;
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventData, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QmlProfiler::Internal::QV8EventSub, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
namespace QmlProfiler {
namespace Internal {
QV8EventData &QV8EventData::operator=(const QV8EventData &ref)
{
if (this == &ref)
return *this;
displayName = ref.displayName;
eventHashStr = ref.eventHashStr;
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;
}
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();
}
class QV8ProfilerDataModel::QV8ProfilerDataModelPrivate
{
public:
QV8ProfilerDataModelPrivate(QV8ProfilerDataModel *qq) {Q_UNUSED(qq);}
QmlProfilerDataModel *qmlProfilerDataModel;
void clearV8RootEvent();
void collectV8Statistics();
QHash<QString, QV8EventData *> v8EventHash;
QHash<int, QV8EventData *> v8parents;
QV8EventData v8RootEvent;
qint64 v8MeasuredTime;
};
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent,
QmlProfilerDataModel *profilerDataModel)
: QObject(parent), d(new QV8ProfilerDataModelPrivate(this))
{
d->v8MeasuredTime = 0;
d->clearV8RootEvent();
d->qmlProfilerDataModel = profilerDataModel;
}
QV8ProfilerDataModel::~QV8ProfilerDataModel()
{
delete d;
}
void QV8ProfilerDataModel::clear()
{
qDeleteAll(d->v8EventHash.values());
d->v8EventHash.clear();
d->v8parents.clear();
d->clearV8RootEvent();
d->v8MeasuredTime = 0;
}
bool QV8ProfilerDataModel::isEmpty() const
{
return d->v8EventHash.isEmpty();
}
QV8EventData *QV8ProfilerDataModel::v8EventDescription(int eventId) const
{
foreach (QV8EventData *event, d->v8EventHash.values()) {
if (event->eventId == eventId)
return event;
}
return 0;
}
qint64 QV8ProfilerDataModel::v8MeasuredTime() const
{
return d->v8MeasuredTime;
}
QList<QV8EventData *> QV8ProfilerDataModel::getV8Events() const
{
return d->v8EventHash.values();
}
void QV8ProfilerDataModel::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 hashStr = QmlProfilerDataModel::getHashStringForV8Event(displayName, function);
d->qmlProfilerDataModel->setState(QmlProfilerDataModel::AcquiringData);
// time is given in milliseconds, but internally we store it in microseconds
totalTime *= 1e6;
selfTime *= 1e6;
// accumulate information
QV8EventData *eventData = d->v8EventHash[hashStr];
if (!eventData) {
eventData = new QV8EventData;
eventData->displayName = displayName;
eventData->eventHashStr = hashStr;
eventData->filename = filename;
eventData->functionName = function;
eventData->line = lineNumber;
eventData->totalTime = totalTime;
eventData->selfTime = selfTime;
d->v8EventHash[hashStr] = eventData;
} else {
eventData->totalTime += totalTime;
eventData->selfTime += selfTime;
}
d->v8parents[depth] = eventData;
QV8EventData *parentEvent = 0;
if (depth == 0) {
parentEvent = &d->v8RootEvent;
d->v8MeasuredTime += totalTime;
}
if (depth > 0 && d->v8parents.contains(depth-1)) {
parentEvent = d->v8parents.value(depth-1);
}
if (parentEvent != 0) {
if (!eventData->parentHash.contains(parentEvent->eventHashStr)) {
QV8EventSub *newParentSub = new QV8EventSub(parentEvent);
newParentSub->totalTime = totalTime;
eventData->parentHash.insert(parentEvent->eventHashStr, newParentSub);
} else {
QV8EventSub *newParentSub = eventData->parentHash.value(parentEvent->eventHashStr);
newParentSub->totalTime += totalTime;
}
if (!parentEvent->childrenHash.contains(eventData->eventHashStr)) {
QV8EventSub *newChildSub = new QV8EventSub(eventData);
newChildSub->totalTime = totalTime;
parentEvent->childrenHash.insert(eventData->eventHashStr, newChildSub);
} else {
QV8EventSub *newChildSub = parentEvent->childrenHash.value(eventData->eventHashStr);
newChildSub->totalTime += totalTime;
}
}
}
void QV8ProfilerDataModel::collectV8Statistics()
{
d->collectV8Statistics();
}
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::collectV8Statistics()
{
if (!v8EventHash.isEmpty()) {
double totalTimes = v8MeasuredTime;
double selfTimes = 0;
foreach (QV8EventData *v8event, v8EventHash.values()) {
selfTimes += v8event->selfTime;
}
// prevent divisions by 0
if (totalTimes == 0)
totalTimes = 1;
if (selfTimes == 0)
selfTimes = 1;
// insert root event in eventlist
// the +1 ns is to get it on top of the sorted list
v8RootEvent.totalTime = v8MeasuredTime + 1;
v8RootEvent.selfTime = 0;
QString rootEventHash = QmlProfilerDataModel::getHashStringForV8Event(
QmlProfilerDataModel::rootEventName(),
QmlProfilerDataModel::rootEventDescription());
QV8EventData *v8RootEventPointer = v8EventHash[rootEventHash];
if (v8RootEventPointer) {
v8RootEvent = *v8RootEventPointer;
} else {
v8EventHash[rootEventHash] = new QV8EventData;
*v8EventHash[rootEventHash] = v8RootEvent;
}
foreach (QV8EventData *v8event, v8EventHash.values()) {
v8event->totalPercent = v8event->totalTime * 100.0 / totalTimes;
v8event->selfPercent = v8event->selfTime * 100.0 / selfTimes;
}
int index = 0;
foreach (QV8EventData *v8event, v8EventHash.values()) {
v8event->eventId = index++;
}
v8RootEvent.eventId = v8EventHash[rootEventHash]->eventId;
}
}
void QV8ProfilerDataModel::QV8ProfilerDataModelPrivate::clearV8RootEvent()
{
v8RootEvent.displayName = QmlProfilerDataModel::rootEventName();
v8RootEvent.eventHashStr = QmlProfilerDataModel::rootEventName();
v8RootEvent.functionName = QmlProfilerDataModel::rootEventDescription();
v8RootEvent.line = -1;
v8RootEvent.totalTime = 0;
v8RootEvent.totalPercent = 0;
v8RootEvent.selfTime = 0;
v8RootEvent.selfPercent = 0;
v8RootEvent.eventId = -1;
qDeleteAll(v8RootEvent.parentHash.values());
qDeleteAll(v8RootEvent.childrenHash.values());
v8RootEvent.parentHash.clear();
v8RootEvent.childrenHash.clear();
}
void QV8ProfilerDataModel::save(QXmlStreamWriter &stream)
{
stream.writeStartElement("v8profile"); // v8 profiler output
stream.writeAttribute("totalTime", QString::number(d->v8MeasuredTime));
foreach (QV8EventData *v8event, d->v8EventHash.values()) {
stream.writeStartElement("event");
stream.writeAttribute("index",
QString::number(
d->v8EventHash.keys().indexOf(
v8event->eventHashStr)));
stream.writeTextElement("displayname", v8event->displayName);
stream.writeTextElement("functionname", v8event->functionName);
if (!v8event->filename.isEmpty()) {
stream.writeTextElement("filename", v8event->filename);
stream.writeTextElement("line", QString::number(v8event->line));
}
stream.writeTextElement("totalTime", QString::number(v8event->totalTime));
stream.writeTextElement("selfTime", QString::number(v8event->selfTime));
if (!v8event->childrenHash.isEmpty()) {
stream.writeStartElement("childrenEvents");
QStringList childrenIndexes;
QStringList childrenTimes;
QStringList parentTimes;
foreach (QV8EventSub *v8child, v8event->childrenHash.values()) {
childrenIndexes << QString::number(v8child->reference->eventId);
childrenTimes << QString::number(v8child->totalTime);
parentTimes << QString::number(v8child->totalTime);
}
stream.writeAttribute("list", childrenIndexes.join(QString(", ")));
stream.writeAttribute("childrenTimes", childrenTimes.join(QString(", ")));
stream.writeAttribute("parentTimes", parentTimes.join(QString(", ")));
stream.writeEndElement();
}
stream.writeEndElement();
}
stream.writeEndElement(); // v8 profiler output
}
void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
{
QHash <int, QV8EventData *> v8eventBuffer;
QHash <int, QString> childrenIndexes;
QHash <int, QString> childrenTimes;
QHash <int, QString> parentTimes;
QV8EventData *v8event = 0;
// time computation
d->v8MeasuredTime = 0;
double cumulatedV8Time = 0;
// get the v8 time
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute("totalTime"))
d->v8MeasuredTime = attributes.value("totalTime").toString().toDouble();
while (!stream.atEnd() && !stream.hasError()) {
QXmlStreamReader::TokenType token = stream.readNext();
QString elementName = stream.name().toString();
switch (token) {
case QXmlStreamReader::StartDocument : continue;
case QXmlStreamReader::StartElement : {
if (elementName == "event") {
QXmlStreamAttributes attributes = stream.attributes();
if (attributes.hasAttribute("index")) {
int ndx = attributes.value("index").toString().toInt();
if (!v8eventBuffer.value(ndx))
v8eventBuffer[ndx] = new QV8EventData;
v8event = v8eventBuffer[ndx];
} else {
v8event = 0;
}
break;
}
if (!v8event)
break;
if (elementName == "childrenEvents") {
QXmlStreamAttributes attributes = stream.attributes();
int eventIndex = v8eventBuffer.key(v8event);
if (attributes.hasAttribute("list")) {
// store for later parsing (we haven't read all the events yet)
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();
}
}
stream.readNext();
if (stream.tokenType() != QXmlStreamReader::Characters)
break;
QString readData = stream.text().toString();
if (elementName == "displayname") {
v8event->displayName = readData;
break;
}
if (elementName == "functionname") {
v8event->functionName = readData;
break;
}
if (elementName == "filename") {
v8event->filename = readData;
break;
}
if (elementName == "line") {
v8event->line = readData.toInt();
break;
}
if (elementName == "totalTime") {
v8event->totalTime = readData.toDouble();
cumulatedV8Time += v8event->totalTime;
break;
}
if (elementName == "selfTime") {
v8event->selfTime = readData.toDouble();
break;
}
break;
}
case QXmlStreamReader::EndElement : {
if (elementName == "v8profile") {
// done reading the v8 profile data
break;
}
}
default: break;
}
}
// backwards compatibility
if (d->v8MeasuredTime == 0)
d->v8MeasuredTime = cumulatedV8Time;
// find v8events' children and parents
foreach (int parentIndex, childrenIndexes.keys()) {
QStringList childrenStrings = childrenIndexes.value(parentIndex).split(",");
QStringList childrenTimesStrings = childrenTimes.value(parentIndex).split(", ");
QStringList parentTimesStrings = parentTimes.value(parentIndex).split(", ");
for (int ndx = 0; ndx < childrenStrings.count(); ndx++) {
int childIndex = childrenStrings[ndx].toInt();
if (v8eventBuffer.value(childIndex)) {
QV8EventSub *newChild = new QV8EventSub(v8eventBuffer[childIndex]);
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);
}
}
}
// store v8 events
foreach (QV8EventData *storedV8Event, v8eventBuffer.values()) {
storedV8Event->eventHashStr =
QmlProfilerDataModel::getHashStringForV8Event(
storedV8Event->displayName, storedV8Event->functionName);
d->v8EventHash[storedV8Event->eventHashStr] = storedV8Event;
}
d->collectV8Statistics();
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -0,0 +1,79 @@
#ifndef QV8PROFILERDATAMODEL_H
#define QV8PROFILERDATAMODEL_H
#include <QObject>
#include <QHash>
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
namespace QmlProfiler {
namespace Internal {
class QmlProfilerDataModel;
struct QV8EventSub;
struct QV8EventData
{
QV8EventData();
~QV8EventData();
QString displayName;
QString eventHashStr;
QString filename;
QString functionName;
int line;
double totalTime; // given in milliseconds
double totalPercent;
double selfTime;
double selfPercent;
QHash <QString, QV8EventSub *> parentHash;
QHash <QString, QV8EventSub *> childrenHash;
int eventId;
QV8EventData &operator=(const QV8EventData &ref);
};
struct QV8EventSub {
QV8EventSub(QV8EventData *from) : reference(from), totalTime(0) {}
QV8EventSub(QV8EventSub *from) : reference(from->reference), totalTime(from->totalTime) {}
QV8EventData *reference;
qint64 totalTime;
};
class QV8ProfilerDataModel : public QObject
{
Q_OBJECT
public:
explicit QV8ProfilerDataModel(QObject *parent, QmlProfilerDataModel *profilerDataModel);
~QV8ProfilerDataModel();
void clear();
bool isEmpty() const;
QList<QV8EventData *> getV8Events() const;
QV8EventData *v8EventDescription(int eventId) const;
qint64 v8MeasuredTime() const;
void collectV8Statistics();
void save(QXmlStreamWriter &stream);
void load(QXmlStreamReader &stream);
public slots:
void addV8Event(int depth,
const QString &function,
const QString &filename,
int lineNumber,
double totalTime,
double selfTime);
private:
class QV8ProfilerDataModelPrivate;
QV8ProfilerDataModelPrivate *d;
};
} // namespace Internal
} // namespace QmlProfiler
#endif // QV8PROFILERDATAMODEL_H

View File

@@ -30,7 +30,7 @@
**
**************************************************************************/
#include "timelineview.h"
#include "timelinerenderer.h"
#include <qdeclarativecontext.h>
#include <qdeclarativeproperty.h>
@@ -45,9 +45,9 @@ using namespace QmlProfiler::Internal;
const int DefaultRowHeight = 30;
TimelineView::TimelineView(QDeclarativeItem *parent) :
TimelineRenderer::TimelineRenderer(QDeclarativeItem *parent) :
QDeclarativeItem(parent), m_startTime(0), m_endTime(0), m_spacing(0),
m_lastStartTime(0), m_lastEndTime(0), m_eventList(0)
m_lastStartTime(0), m_lastEndTime(0), m_profilerDataModel(0)
{
clearData();
setFlag(QGraphicsItem::ItemHasNoContents, false);
@@ -57,12 +57,12 @@ TimelineView::TimelineView(QDeclarativeItem *parent) :
m_rowsExpanded << false;
}
void TimelineView::componentComplete()
void TimelineRenderer::componentComplete()
{
const QMetaObject *metaObject = this->metaObject();
int propertyCount = metaObject->propertyCount();
int requestPaintMethod = metaObject->indexOfMethod("requestPaint()");
for (int ii = TimelineView::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
for (int ii = TimelineRenderer::staticMetaObject.propertyCount(); ii < propertyCount; ++ii) {
QMetaProperty p = metaObject->property(ii);
if (p.hasNotifySignal())
QMetaObject::connect(this, p.notifySignalIndex(), this, requestPaintMethod, 0, 0);
@@ -70,12 +70,12 @@ void TimelineView::componentComplete()
QDeclarativeItem::componentComplete();
}
void TimelineView::requestPaint()
void TimelineRenderer::requestPaint()
{
update();
}
void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
void TimelineRenderer::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
qint64 windowDuration = m_endTime - m_startTime;
if (windowDuration <= 0)
@@ -86,7 +86,8 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
m_rowWidths.clear();
// The "1+" is because the reference screenshot features an empty row per type, in order to leave space for the title
for (int i=0; i<QmlJsDebugClient::MaximumQmlEventType; i++) {
m_rowWidths << 1 + (m_rowsExpanded[i] ? m_eventList->uniqueEventsOfType(i) : m_eventList->maxNestingForType(i));
m_rowWidths << 1 + (m_rowsExpanded[i] ? m_profilerDataModel->uniqueEventsOfType(i) :
m_profilerDataModel->maxNestingForType(i));
}
// event rows
@@ -105,8 +106,8 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
for (int j=0; j<m_rowWidths[i]; j++)
m_rowLastX << -m_startTime * m_spacing;
int firstIndex = m_eventList->findFirstIndex(m_startTime);
int lastIndex = m_eventList->findLastIndex(m_endTime);
int firstIndex = m_profilerDataModel->findFirstIndex(m_startTime);
int lastIndex = m_profilerDataModel->findLastIndex(m_endTime);
drawItemsToPainter(p, firstIndex, lastIndex);
drawSelectionBoxes(p, firstIndex, lastIndex);
@@ -116,25 +117,27 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
m_lastEndTime = m_endTime;
}
QColor TimelineView::colorForItem(int itemIndex)
QColor TimelineRenderer::colorForItem(int itemIndex)
{
int ndx = m_eventList->getEventId(itemIndex);
int ndx = m_profilerDataModel->getEventId(itemIndex);
return QColor::fromHsl((ndx*25)%360, 76, 166);
}
void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
void TimelineRenderer::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
{
int x, y, width, height, rowNumber, eventType;
for (int i = fromIndex; i <= toIndex; i++) {
x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing;
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
eventType = m_eventList->getType(i);
eventType = m_profilerDataModel->getType(i);
if (m_rowsExpanded[eventType])
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1);
y = m_rowStarts[eventType] + DefaultRowHeight *
(m_profilerDataModel->eventPosInType(i) + 1);
else
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
y = m_rowStarts[eventType] + DefaultRowHeight *
m_profilerDataModel->getNestingLevel(i);
width = m_eventList->getDuration(i)*m_spacing;
width = m_profilerDataModel->getDuration(i)*m_spacing;
if (width<1)
width = 1;
@@ -144,17 +147,19 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
m_rowLastX[rowNumber] = x+width;
// special: animations
if (eventType == 0 && m_eventList->getAnimationCount(i) >= 0) {
double scale = m_eventList->getMaximumAnimationCount() - m_eventList->getMinimumAnimationCount();
if (eventType == 0 && m_profilerDataModel->getAnimationCount(i) >= 0) {
double scale = m_profilerDataModel->getMaximumAnimationCount() -
m_profilerDataModel->getMinimumAnimationCount();
double fraction;
if (scale > 1)
fraction = (double)(m_eventList->getAnimationCount(i) - m_eventList->getMinimumAnimationCount()) / scale;
fraction = (double)(m_profilerDataModel->getAnimationCount(i) -
m_profilerDataModel->getMinimumAnimationCount()) / scale;
else
fraction = 1.0;
height = DefaultRowHeight * (fraction * 0.85 + 0.15);
y += DefaultRowHeight - height;
double fpsFraction = m_eventList->getFramerate(i) / 60.0;
double fpsFraction = m_profilerDataModel->getFramerate(i) / 60.0;
if (fpsFraction > 1.0)
fpsFraction = 1.0;
p->setBrush(QColor::fromHsl((fpsFraction*96)+10, 76, 166));
@@ -167,12 +172,12 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
}
}
void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
void TimelineRenderer::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
{
if (m_selectedItem == -1)
return;
int id = m_eventList->getEventId(m_selectedItem);
int id = m_profilerDataModel->getEventId(m_selectedItem);
p->setBrush(Qt::transparent);
QColor selectionColor = Qt::blue;
@@ -188,17 +193,19 @@ void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
QRect selectedItemRect(0,0,0,0);
for (int i = fromIndex; i <= toIndex; i++) {
if (m_eventList->getEventId(i) != id)
if (m_profilerDataModel->getEventId(i) != id)
continue;
x = (m_eventList->getStartTime(i) - m_startTime) * m_spacing;
eventType = m_eventList->getType(i);
x = (m_profilerDataModel->getStartTime(i) - m_startTime) * m_spacing;
eventType = m_profilerDataModel->getType(i);
if (m_rowsExpanded[eventType])
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(i) + 1);
y = m_rowStarts[eventType] + DefaultRowHeight *
(m_profilerDataModel->eventPosInType(i) + 1);
else
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
y = m_rowStarts[eventType] + DefaultRowHeight *
m_profilerDataModel->getNestingLevel(i);
width = m_eventList->getDuration(i)*m_spacing;
width = m_profilerDataModel->getDuration(i)*m_spacing;
if (width<1)
width = 1;
@@ -215,7 +222,7 @@ void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
}
}
void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
void TimelineRenderer::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
{
int destindex;
int xfrom, xto, eventType;
@@ -228,35 +235,38 @@ void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toInde
p->save();
for (int i = fromIndex; i <= toIndex; i++) {
destindex = m_eventList->getBindingLoopDest(i);
destindex = m_profilerDataModel->getBindingLoopDest(i);
if (destindex >= 0) {
// from
xfrom = (m_eventList->getStartTime(i) + m_eventList->getDuration(i)/2 -
xfrom = (m_profilerDataModel->getStartTime(i) +
m_profilerDataModel->getDuration(i)/2 -
m_startTime) * m_spacing;
eventType = m_eventList->getType(i);
eventType = m_profilerDataModel->getType(i);
if (m_rowsExpanded[eventType])
yfrom = m_rowStarts[eventType] + DefaultRowHeight*
(m_eventList->eventPosInType(i) + 1);
(m_profilerDataModel->eventPosInType(i) + 1);
else
yfrom = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
yfrom = m_rowStarts[eventType] + DefaultRowHeight *
m_profilerDataModel->getNestingLevel(i);
yfrom += DefaultRowHeight / 2;
// to
xto = (m_eventList->getStartTime(destindex) + m_eventList->getDuration(destindex)/2 -
xto = (m_profilerDataModel->getStartTime(destindex) +
m_profilerDataModel->getDuration(destindex)/2 -
m_startTime) * m_spacing;
eventType = m_eventList->getType(destindex);
eventType = m_profilerDataModel->getType(destindex);
if (m_rowsExpanded[eventType])
yto = m_rowStarts[eventType] + DefaultRowHeight*
(m_eventList->eventPosInType(destindex) + 1);
yto = m_rowStarts[eventType] + DefaultRowHeight *
(m_profilerDataModel->eventPosInType(destindex) + 1);
else
yto = m_rowStarts[eventType] + DefaultRowHeight *
m_eventList->getNestingLevel(destindex);
m_profilerDataModel->getNestingLevel(destindex);
yto += DefaultRowHeight / 2;
// radius
int eventWidth = m_eventList->getDuration(i) * m_spacing;
int eventWidth = m_profilerDataModel->getDuration(i) * m_spacing;
radius = 5;
if (radius * 2 > eventWidth)
radius = eventWidth / 2;
@@ -283,7 +293,7 @@ void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toInde
p->restore();
}
void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
void TimelineRenderer::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
// special case: if there is a drag area below me, don't accept the
// events unless I'm actually clicking inside an item
@@ -294,19 +304,19 @@ void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
}
void TimelineView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
void TimelineRenderer::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
manageClicked();
}
void TimelineView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void TimelineRenderer::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
event->setAccepted(false);
}
void TimelineView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
void TimelineRenderer::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
Q_UNUSED(event);
manageHovered(event->pos().x(), event->pos().y());
@@ -314,7 +324,7 @@ void TimelineView::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
event->setAccepted(false);
}
void TimelineView::manageClicked()
void TimelineRenderer::manageClicked()
{
if (m_currentSelection.eventIndex != -1) {
if (m_currentSelection.eventIndex == m_selectedItem)
@@ -328,7 +338,7 @@ void TimelineView::manageClicked()
setSelectedItem(m_currentSelection.eventIndex);
}
void TimelineView::manageHovered(int x, int y)
void TimelineRenderer::manageHovered(int x, int y)
{
if (m_endTime - m_startTime <=0 || m_lastEndTime - m_lastStartTime <= 0)
return;
@@ -337,13 +347,16 @@ void TimelineView::manageHovered(int x, int y)
int row = y / DefaultRowHeight;
// already covered? nothing to do
if (m_currentSelection.eventIndex != -1 && time >= m_currentSelection.startTime && time <= m_currentSelection.endTime && row == m_currentSelection.row) {
if (m_currentSelection.eventIndex != -1 &&
time >= m_currentSelection.startTime &&
time <= m_currentSelection.endTime &&
row == m_currentSelection.row) {
return;
}
// find if there's items in the time range
int eventFrom = m_eventList->findFirstIndex(time);
int eventTo = m_eventList->findLastIndex(time);
int eventFrom = m_profilerDataModel->findFirstIndex(time);
int eventTo = m_profilerDataModel->findLastIndex(time);
if (eventTo < eventFrom) {
m_currentSelection.eventIndex = -1;
return;
@@ -352,19 +365,21 @@ void TimelineView::manageHovered(int x, int y)
// find if we are in the right column
int itemRow, eventType;
for (int i=eventTo; i>=eventFrom; --i) {
if (ceil(m_eventList->getEndTime(i)*m_spacing) < floor(time*m_spacing))
if (ceil(m_profilerDataModel->getEndTime(i)*m_spacing) < floor(time*m_spacing))
continue;
eventType = m_eventList->getType(i);
eventType = m_profilerDataModel->getType(i);
if (m_rowsExpanded[eventType])
itemRow = m_rowStarts[eventType]/DefaultRowHeight + m_eventList->eventPosInType(i) + 1;
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
m_profilerDataModel->eventPosInType(i) + 1;
else
itemRow = m_rowStarts[eventType]/DefaultRowHeight + m_eventList->getNestingLevel(i);
itemRow = m_rowStarts[eventType]/DefaultRowHeight +
m_profilerDataModel->getNestingLevel(i);
if (itemRow == row) {
// match
m_currentSelection.eventIndex = i;
m_currentSelection.startTime = m_eventList->getStartTime(i);
m_currentSelection.endTime = m_eventList->getEndTime(i);
m_currentSelection.startTime = m_profilerDataModel->getStartTime(i);
m_currentSelection.endTime = m_profilerDataModel->getEndTime(i);
m_currentSelection.row = row;
if (!m_selectionLocked)
setSelectedItem(i);
@@ -376,7 +391,7 @@ void TimelineView::manageHovered(int x, int y)
return;
}
void TimelineView::clearData()
void TimelineRenderer::clearData()
{
m_startTime = 0;
m_endTime = 0;
@@ -390,122 +405,125 @@ void TimelineView::clearData()
m_selectionLocked = true;
}
qint64 TimelineView::getDuration(int index) const
qint64 TimelineRenderer::getDuration(int index) const
{
Q_ASSERT(m_eventList);
return m_eventList->getEndTime(index) - m_eventList->getStartTime(index);
Q_ASSERT(m_profilerDataModel);
return m_profilerDataModel->getEndTime(index) -
m_profilerDataModel->getStartTime(index);
}
QString TimelineView::getFilename(int index) const
QString TimelineRenderer::getFilename(int index) const
{
Q_ASSERT(m_eventList);
return m_eventList->getFilename(index);
Q_ASSERT(m_profilerDataModel);
return m_profilerDataModel->getFilename(index);
}
int TimelineView::getLine(int index) const
int TimelineRenderer::getLine(int index) const
{
Q_ASSERT(m_eventList);
return m_eventList->getLine(index);
Q_ASSERT(m_profilerDataModel);
return m_profilerDataModel->getLine(index);
}
QString TimelineView::getDetails(int index) const
QString TimelineRenderer::getDetails(int index) const
{
Q_ASSERT(m_eventList);
return m_eventList->getDetails(index);
Q_ASSERT(m_profilerDataModel);
return m_profilerDataModel->getDetails(index);
}
int TimelineView::getYPosition(int index) const
int TimelineRenderer::getYPosition(int index) const
{
Q_ASSERT(m_eventList);
if (index >= m_eventList->count() || m_rowStarts.isEmpty())
Q_ASSERT(m_profilerDataModel);
if (index >= m_profilerDataModel->count() || m_rowStarts.isEmpty())
return 0;
int y, eventType = m_eventList->getType(index);
int y, eventType = m_profilerDataModel->getType(index);
if (m_rowsExpanded[eventType])
y = m_rowStarts[eventType] + DefaultRowHeight*(m_eventList->eventPosInType(index) + 1);
y = m_rowStarts[eventType] + DefaultRowHeight *
(m_profilerDataModel->eventPosInType(index) + 1);
else
y = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(index);
y = m_rowStarts[eventType] + DefaultRowHeight *
m_profilerDataModel->getNestingLevel(index);
return y;
}
void TimelineView::setRowExpanded(int rowIndex, bool expanded)
void TimelineRenderer::setRowExpanded(int rowIndex, bool expanded)
{
m_rowsExpanded[rowIndex] = expanded;
update();
}
void TimelineView::selectNext()
void TimelineRenderer::selectNext()
{
if (m_eventList->count() == 0)
if (m_profilerDataModel->count() == 0)
return;
// select next in view or after
int newIndex = m_selectedItem+1;
if (newIndex >= m_eventList->count())
if (newIndex >= m_profilerDataModel->count())
newIndex = 0;
if (m_eventList->getEndTime(newIndex) < m_startTime)
newIndex = m_eventList->findFirstIndexNoParents(m_startTime);
if (m_profilerDataModel->getEndTime(newIndex) < m_startTime)
newIndex = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
setSelectedItem(newIndex);
}
void TimelineView::selectPrev()
void TimelineRenderer::selectPrev()
{
if (m_eventList->count() == 0)
if (m_profilerDataModel->count() == 0)
return;
// select last in view or before
int newIndex = m_selectedItem-1;
if (newIndex < 0)
newIndex = m_eventList->count()-1;
if (m_eventList->getStartTime(newIndex) > m_endTime)
newIndex = m_eventList->findLastIndex(m_endTime);
newIndex = m_profilerDataModel->count()-1;
if (m_profilerDataModel->getStartTime(newIndex) > m_endTime)
newIndex = m_profilerDataModel->findLastIndex(m_endTime);
setSelectedItem(newIndex);
}
int TimelineView::nextItemFromId(int eventId) const
int TimelineRenderer::nextItemFromId(int eventId) const
{
int ndx = -1;
if (m_selectedItem == -1)
ndx = m_eventList->findFirstIndexNoParents(m_startTime);
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
else
ndx = m_selectedItem + 1;
if (ndx >= m_eventList->count())
if (ndx >= m_profilerDataModel->count())
ndx = 0;
int startIndex = ndx;
do {
if (m_eventList->getEventId(ndx) == eventId)
if (m_profilerDataModel->getEventId(ndx) == eventId)
return ndx;
ndx = (ndx + 1) % m_eventList->count();
ndx = (ndx + 1) % m_profilerDataModel->count();
} while (ndx != startIndex);
return -1;
}
int TimelineView::prevItemFromId(int eventId) const
int TimelineRenderer::prevItemFromId(int eventId) const
{
int ndx = -1;
if (m_selectedItem == -1)
ndx = m_eventList->findFirstIndexNoParents(m_startTime);
ndx = m_profilerDataModel->findFirstIndexNoParents(m_startTime);
else
ndx = m_selectedItem - 1;
if (ndx < 0)
ndx = m_eventList->count() - 1;
ndx = m_profilerDataModel->count() - 1;
int startIndex = ndx;
do {
if (m_eventList->getEventId(ndx) == eventId)
if (m_profilerDataModel->getEventId(ndx) == eventId)
return ndx;
if (--ndx < 0)
ndx = m_eventList->count()-1;
ndx = m_profilerDataModel->count()-1;
} while (ndx != startIndex);
return -1;
}
void TimelineView::selectNextFromId(int eventId)
void TimelineRenderer::selectNextFromId(int eventId)
{
int eventIndex = nextItemFromId(eventId);
if (eventIndex != -1)
setSelectedItem(eventIndex);
}
void TimelineView::selectPrevFromId(int eventId)
void TimelineRenderer::selectPrevFromId(int eventId)
{
int eventIndex = prevItemFromId(eventId);
if (eventIndex != -1)

View File

@@ -30,29 +30,29 @@
**
**************************************************************************/
#ifndef TIMELINEVIEW_H
#define TIMELINEVIEW_H
#ifndef TIMELINERENDERER_H
#define TIMELINERENDERER_H
#include <QDeclarativeItem>
#include <QScriptValue>
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include "qmlprofilerdatamodel.h"
namespace QmlProfiler {
namespace Internal {
class TimelineView : public QDeclarativeItem
class TimelineRenderer : public QDeclarativeItem
{
Q_OBJECT
Q_PROPERTY(qint64 startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
Q_PROPERTY(qint64 endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged)
Q_PROPERTY(QObject* eventList READ eventList WRITE setEventList NOTIFY eventListChanged)
Q_PROPERTY(QObject* profilerDataModel READ profilerDataModel WRITE setProfilerDataModel NOTIFY profilerDataModelChanged)
Q_PROPERTY(bool selectionLocked READ selectionLocked WRITE setSelectionLocked NOTIFY selectionLockedChanged)
Q_PROPERTY(int selectedItem READ selectedItem WRITE setSelectedItem NOTIFY selectedItemChanged)
Q_PROPERTY(int startDragArea READ startDragArea WRITE setStartDragArea NOTIFY startDragAreaChanged)
Q_PROPERTY(int endDragArea READ endDragArea WRITE setEndDragArea NOTIFY endDragAreaChanged)
public:
explicit TimelineView(QDeclarativeItem *parent = 0);
explicit TimelineRenderer(QDeclarativeItem *parent = 0);
qint64 startTime() const
{
@@ -84,11 +84,11 @@ public:
return m_endDragArea;
}
QmlJsDebugClient::QmlProfilerEventList *eventList() const { return m_eventList; }
void setEventList(QObject *eventList)
QmlProfilerDataModel *profilerDataModel() const { return m_profilerDataModel; }
void setProfilerDataModel(QObject *profilerDataModel)
{
m_eventList = qobject_cast<QmlJsDebugClient::QmlProfilerEventList *>(eventList);
emit eventListChanged(m_eventList);
m_profilerDataModel = qobject_cast<QmlProfilerDataModel *>(profilerDataModel);
emit profilerDataModelChanged(m_profilerDataModel);
}
Q_INVOKABLE qint64 getDuration(int index) const;
@@ -109,7 +109,7 @@ public:
signals:
void startTimeChanged(qint64 arg);
void endTimeChanged(qint64 arg);
void eventListChanged(QmlJsDebugClient::QmlProfilerEventList *list);
void profilerDataModelChanged(QmlProfilerDataModel *list);
void selectionLockedChanged(bool locked);
void selectedItemChanged(int itemIndex);
void startDragAreaChanged(int startDragArea);
@@ -195,7 +195,7 @@ private:
qint64 m_lastStartTime;
qint64 m_lastEndTime;
QmlJsDebugClient::QmlProfilerEventList *m_eventList;
QmlProfilerDataModel *m_profilerDataModel;
QList<int> m_rowLastX;
QList<int> m_rowStarts;
@@ -218,6 +218,6 @@ private:
} // namespace Internal
} // namespace QmlProfiler
QML_DECLARE_TYPE(QmlProfiler::Internal::TimelineView)
QML_DECLARE_TYPE(QmlProfiler::Internal::TimelineRenderer)
#endif // TIMELINEVIEW_H
#endif // TIMELINERENDERER_H

View File

@@ -1,649 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "tracewindow.h"
#include "qmlprofilerplugin.h"
#include <qmljsdebugclient/qmlprofilereventlist.h>
#include <qmljsdebugclient/qmlprofilertraceclient.h>
#include <utils/styledbar.h>
#include <QDeclarativeView>
#include <QDeclarativeContext>
#include <QVBoxLayout>
#include <QGraphicsObject>
#include <QContextMenuEvent>
#include <QScrollBar>
#include <QSlider>
#include <QWidget>
#include <math.h>
using namespace QmlJsDebugClient;
namespace QmlProfiler {
namespace Internal {
const int sliderTicks = 10000;
const qreal sliderExp = 3;
void ZoomControl::setRange(qint64 startTime, qint64 endTime)
{
if (m_startTime != startTime || m_endTime != endTime) {
m_startTime = startTime;
m_endTime = endTime;
emit rangeChanged();
}
}
ScrollableDeclarativeView::ScrollableDeclarativeView(QWidget *parent)
: QDeclarativeView(parent)
{
}
ScrollableDeclarativeView::~ScrollableDeclarativeView()
{
}
void ScrollableDeclarativeView::scrollContentsBy(int dx, int dy)
{
// special workaround to track the scrollbar
if (rootObject()) {
int scrollY = rootObject()->property("scrollY").toInt();
rootObject()->setProperty("scrollY", QVariant(scrollY - dy));
}
QDeclarativeView::scrollContentsBy(dx,dy);
}
TraceWindow::TraceWindow(QWidget *parent)
: QWidget(parent)
{
setObjectName("QML Profiler");
m_zoomControl = new ZoomControl(this);
connect(m_zoomControl.data(), SIGNAL(rangeChanged()), this, SLOT(updateRange()));
QVBoxLayout *groupLayout = new QVBoxLayout;
groupLayout->setContentsMargins(0, 0, 0, 0);
groupLayout->setSpacing(0);
m_mainView = new ScrollableDeclarativeView(this);
m_mainView->setResizeMode(QDeclarativeView::SizeViewToRootObject);
m_mainView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
m_mainView->setBackgroundBrush(QBrush(Qt::white));
m_mainView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_mainView->setFocus();
MouseWheelResizer *resizer = new MouseWheelResizer(this);
connect(resizer,SIGNAL(mouseWheelMoved(int,int,int)), this, SLOT(mouseWheelMoved(int,int,int)));
m_mainView->viewport()->installEventFilter(resizer);
QHBoxLayout *toolsLayout = new QHBoxLayout;
m_timebar = new QDeclarativeView(this);
m_timebar->setResizeMode(QDeclarativeView::SizeRootObjectToView);
m_timebar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_timebar->setFixedHeight(24);
m_overview = new QDeclarativeView(this);
m_overview->setResizeMode(QDeclarativeView::SizeRootObjectToView);
m_overview->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_overview->setMaximumHeight(50);
m_zoomToolbar = createZoomToolbar();
m_zoomToolbar->move(0, m_timebar->height());
m_zoomToolbar->setVisible(false);
toolsLayout->addWidget(createToolbar());
toolsLayout->addWidget(m_timebar);
groupLayout->addLayout(toolsLayout);
groupLayout->addWidget(m_mainView);
groupLayout->addWidget(m_overview);
setLayout(groupLayout);
m_eventList = new QmlProfilerEventList(this);
connect(this,SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)), m_eventList, SLOT(addRangedEvent(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
connect(this, SIGNAL(traceFinished(qint64)), m_eventList, SLOT(setTraceEndTime(qint64)));
connect(this, SIGNAL(traceStarted(qint64)), m_eventList, SLOT(setTraceStartTime(qint64)));
connect(this, SIGNAL(frameEvent(qint64,int,int)), m_eventList, SLOT(addFrameEvent(qint64,int,int)));
connect(m_eventList, SIGNAL(stateChanged()), this, SLOT(eventListStateChanged()));
m_mainView->rootContext()->setContextProperty("qmlEventList", m_eventList);
m_overview->rootContext()->setContextProperty("qmlEventList", m_eventList);
m_rewriter = new QmlProfilerDetailsRewriter(this);
connect(m_eventList, SIGNAL(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)), m_rewriter, SLOT(requestDetailsForLocation(int,QmlJsDebugClient::QmlEventLocation)));
connect(m_rewriter, SIGNAL(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)), m_eventList, SLOT(rewriteDetailsString(int,QmlJsDebugClient::QmlEventLocation,QString)));
connect(m_rewriter, SIGNAL(eventDetailsChanged()), m_eventList, SLOT(finishedRewritingDetails()));
connect(m_eventList, SIGNAL(reloadDocumentsForDetails()), m_rewriter, SLOT(reloadDocuments()));
connect(this, SIGNAL(v8range(int,QString,QString,int,double,double)), m_eventList, SLOT(addV8Event(int,QString,QString,int,double,double)));
// Minimum height: 5 rows of 20 pixels + scrollbar of 50 pixels + 20 pixels margin
setMinimumHeight(170);
m_currentZoomLevel = 0;
m_profiledTime = 0;
}
TraceWindow::~TraceWindow()
{
disconnectClientSignals();
delete m_plugin.data();
delete m_v8plugin.data();
}
QWidget *TraceWindow::createToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QToolButton *buttonPrev= new QToolButton;
buttonPrev->setIcon(QIcon(":/qmlprofiler/ico_prev.png"));
buttonPrev->setToolTip(tr("Jump to previous event"));
connect(buttonPrev, SIGNAL(clicked()), this, SIGNAL(jumpToPrev()));
connect(this, SIGNAL(enableToolbar(bool)), buttonPrev, SLOT(setEnabled(bool)));
QToolButton *buttonNext= new QToolButton;
buttonNext->setIcon(QIcon(":/qmlprofiler/ico_next.png"));
buttonNext->setToolTip(tr("Jump to next event"));
connect(buttonNext, SIGNAL(clicked()), this, SIGNAL(jumpToNext()));
connect(this, SIGNAL(enableToolbar(bool)), buttonNext, SLOT(setEnabled(bool)));
QToolButton *buttonZoomControls = new QToolButton;
buttonZoomControls->setIcon(QIcon(":/qmlprofiler/ico_zoom.png"));
buttonZoomControls->setToolTip(tr("Show zoom slider"));
buttonZoomControls->setCheckable(true);
buttonZoomControls->setChecked(false);
connect(buttonZoomControls, SIGNAL(toggled(bool)), m_zoomToolbar, SLOT(setVisible(bool)));
connect(this, SIGNAL(enableToolbar(bool)), buttonZoomControls, SLOT(setEnabled(bool)));
m_buttonRange = new QToolButton;
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
m_buttonRange->setToolTip(tr("Select range"));
m_buttonRange->setCheckable(true);
m_buttonRange->setChecked(false);
connect(m_buttonRange, SIGNAL(clicked(bool)), this, SLOT(toggleRangeMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), m_buttonRange, SLOT(setEnabled(bool)));
connect(this, SIGNAL(rangeModeChanged(bool)), m_buttonRange, SLOT(setChecked(bool)));
m_buttonLock = new QToolButton;
m_buttonLock->setIcon(QIcon(":/qmlprofiler/ico_selectionmode.png"));
m_buttonLock->setToolTip(tr("View event information on mouseover"));
m_buttonLock->setCheckable(true);
m_buttonLock->setChecked(false);
connect(m_buttonLock, SIGNAL(clicked(bool)), this, SLOT(toggleLockMode(bool)));
connect(this, SIGNAL(enableToolbar(bool)), m_buttonLock, SLOT(setEnabled(bool)));
connect(this, SIGNAL(lockModeChanged(bool)), m_buttonLock, SLOT(setChecked(bool)));
toolBarLayout->addWidget(buttonPrev);
toolBarLayout->addWidget(buttonNext);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(buttonZoomControls);
toolBarLayout->addWidget(new Utils::StyledSeparator());
toolBarLayout->addWidget(m_buttonRange);
toolBarLayout->addWidget(m_buttonLock);
return bar;
}
QWidget *TraceWindow::createZoomToolbar()
{
Utils::StyledBar *bar = new Utils::StyledBar(this);
bar->setSingleRow(true);
bar->setFixedWidth(150);
bar->setFixedHeight(24);
QHBoxLayout *toolBarLayout = new QHBoxLayout(bar);
toolBarLayout->setMargin(0);
toolBarLayout->setSpacing(0);
QSlider *zoomSlider = new QSlider(Qt::Horizontal);
zoomSlider->setFocusPolicy(Qt::NoFocus);
zoomSlider->setRange(1, sliderTicks);
zoomSlider->setInvertedAppearance(true);
zoomSlider->setPageStep(sliderTicks/100);
connect(this, SIGNAL(enableToolbar(bool)), zoomSlider, SLOT(setEnabled(bool)));
connect(zoomSlider, SIGNAL(valueChanged(int)), this, SLOT(setZoomLevel(int)));
connect(this, SIGNAL(zoomLevelChanged(int)), zoomSlider, SLOT(setValue(int)));
zoomSlider->setStyleSheet("\
QSlider:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #444444, stop: 1 #5a5a5a);\
border: 1px #313131;\
height: 20px;\
margin: 0px 0px 0px 0px;\
}\
QSlider::add-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
QSlider::sub-page:horizontal {\
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #5a5a5a, stop: 1 #444444);\
border: 1px #313131;\
}\
");
toolBarLayout->addWidget(zoomSlider);
return bar;
}
void TraceWindow::reset(QDeclarativeDebugConnection *conn)
{
disconnectClientSignals();
delete m_plugin.data();
m_plugin = new QmlProfilerTraceClient(conn);
delete m_v8plugin.data();
m_v8plugin = new QV8ProfilerClient(conn);
connectClientSignals();
m_mainView->rootContext()->setContextProperty("connection", m_plugin.data());
m_mainView->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
m_timebar->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
m_overview->rootContext()->setContextProperty("zoomControl", m_zoomControl.data());
m_timebar->setSource(QUrl("qrc:/qmlprofiler/TimeDisplay.qml"));
m_overview->setSource(QUrl("qrc:/qmlprofiler/Overview.qml"));
m_mainView->setSource(QUrl("qrc:/qmlprofiler/MainView.qml"));
m_mainView->rootObject()->setProperty("width", QVariant(width()));
m_mainView->rootObject()->setProperty("candidateHeight", QVariant(height() - m_timebar->height() - m_overview->height()));
updateToolbar();
connect(m_mainView->rootObject(), SIGNAL(updateCursorPosition()), this, SLOT(updateCursorPosition()));
connect(m_mainView->rootObject(), SIGNAL(updateTimer()), this, SLOT(updateTimer()));
connect(m_mainView->rootObject(), SIGNAL(updateRangeButton()), this, SLOT(updateRangeButton()));
connect(m_mainView->rootObject(), SIGNAL(updateLockButton()), this, SLOT(updateLockButton()));
connect(m_eventList, SIGNAL(countChanged()), this, SLOT(updateToolbar()));
connect(this, SIGNAL(jumpToPrev()), m_mainView->rootObject(), SLOT(prevEvent()));
connect(this, SIGNAL(jumpToNext()), m_mainView->rootObject(), SLOT(nextEvent()));
connect(this, SIGNAL(updateViewZoom(QVariant)), m_mainView->rootObject(), SLOT(updateWindowLength(QVariant)));
connect(this, SIGNAL(wheelZoom(QVariant,QVariant)), m_mainView->rootObject(), SLOT(wheelZoom(QVariant,QVariant)));
connect(this, SIGNAL(globalZoom()), m_mainView->rootObject(), SLOT(globalZoom()));
connect(this, SIGNAL(selectNextEventInDisplay(QVariant)), m_mainView->rootObject(), SLOT(selectNextWithId(QVariant)));
connect(m_mainView->rootObject(), SIGNAL(selectedEventIdChanged(int)), this, SIGNAL(selectedEventIdChanged(int)));
connect(m_mainView->rootObject(), SIGNAL(changeToolTip(QString)), this, SLOT(updateToolTip(QString)));
connect(m_mainView->rootObject(), SIGNAL(updateVerticalScroll(int)), this, SLOT(updateVerticalScroll(int)));
connect(this, SIGNAL(internalClearDisplay()), m_mainView->rootObject(), SLOT(clearAll()));
connect(this,SIGNAL(internalClearDisplay()), m_overview->rootObject(), SLOT(clearDisplay()));
m_v8DataReady = false;
m_qmlDataReady = false;
}
void TraceWindow::connectClientSignals()
{
if (m_plugin) {
connect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
connect(m_plugin.data(), SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
this, SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
connect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64)));
connect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SLOT(manageTraceStart(qint64)));
connect(m_plugin.data(), SIGNAL(frame(qint64,int,int)), this, SIGNAL(frameEvent(qint64,int,int)));
connect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
connect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus()));
connect(m_plugin.data(), SIGNAL(recordingChanged(bool)), this, SIGNAL(recordingChanged(bool)));
}
if (m_v8plugin) {
connect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
connect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
connect(m_v8plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
connect(m_v8plugin.data(), SIGNAL(enabledChanged()), m_v8plugin.data(), SLOT(sendRecordingStatus()));
}
}
void TraceWindow::disconnectClientSignals()
{
if (m_plugin) {
disconnect(m_plugin.data(), SIGNAL(complete()), this, SLOT(qmlComplete()));
disconnect(m_plugin.data(), SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)),
this, SIGNAL(range(int,qint64,qint64,QStringList,QmlJsDebugClient::QmlEventLocation)));
disconnect(m_plugin.data(), SIGNAL(traceFinished(qint64)), this, SIGNAL(traceFinished(qint64)));
disconnect(m_plugin.data(), SIGNAL(traceStarted(qint64)), this, SLOT(manageTraceStart(qint64)));
disconnect(m_plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
disconnect(m_plugin.data(), SIGNAL(enabledChanged()), m_plugin.data(), SLOT(sendRecordingStatus()));
disconnect(m_plugin.data(), SIGNAL(recordingChanged(bool)), this, SIGNAL(recordingChanged(bool)));
}
if (m_v8plugin) {
disconnect(m_v8plugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
disconnect(m_v8plugin.data(), SIGNAL(v8range(int,QString,QString,int,double,double)), this, SIGNAL(v8range(int,QString,QString,int,double,double)));
disconnect(m_v8plugin.data(), SIGNAL(enabledChanged()), this, SLOT(updateProfilerState()));
disconnect(m_v8plugin.data(), SIGNAL(enabledChanged()), m_v8plugin.data(), SLOT(sendRecordingStatus()));
}
}
QmlProfilerEventList *TraceWindow::getEventList() const
{
return m_eventList;
}
ZoomControl *TraceWindow::rangeTimes() const
{
return m_zoomControl.data();
}
void TraceWindow::contextMenuEvent(QContextMenuEvent *ev)
{
emit contextMenuRequested(ev->globalPos());
}
void TraceWindow::updateCursorPosition()
{
emit gotoSourceLocation(m_mainView->rootObject()->property("fileName").toString(),
m_mainView->rootObject()->property("lineNumber").toInt(),
m_mainView->rootObject()->property("columnNumber").toInt());
}
void TraceWindow::updateTimer()
{
m_profiledTime = m_mainView->rootObject()->property("elapsedTime").toDouble();
}
void TraceWindow::correctTimer()
{
// once the data is post-processed, use the eventlist time instead of the qml timer
m_profiledTime = (m_eventList->traceEndTime() - m_eventList->traceStartTime()) / 1.0e9;
if (m_profiledTime < 0)
m_profiledTime = 0;
emit viewUpdated();
}
double TraceWindow::profiledTime() const
{
return m_profiledTime;
}
void TraceWindow::clearDisplay()
{
m_eventList->clear();
if (m_plugin)
m_plugin.data()->clearData();
if (m_v8plugin)
m_v8plugin.data()->clearData();
m_zoomControl.data()->setRange(0,0);
m_profiledTime = 0;
updateVerticalScroll(0);
m_mainView->rootObject()->setProperty("scrollY", QVariant(0));
emit internalClearDisplay();
}
void TraceWindow::updateToolbar()
{
emit enableToolbar(m_eventList && m_eventList->count()>0);
}
void TraceWindow::toggleRangeMode(bool active)
{
bool rangeMode = m_mainView->rootObject()->property("selectionRangeMode").toBool();
if (active != rangeMode) {
if (active)
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
else
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
m_mainView->rootObject()->setProperty("selectionRangeMode", QVariant(active));
}
}
void TraceWindow::updateRangeButton()
{
bool rangeMode = m_mainView->rootObject()->property("selectionRangeMode").toBool();
if (rangeMode)
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselected.png"));
else
m_buttonRange->setIcon(QIcon(":/qmlprofiler/ico_rangeselection.png"));
emit rangeModeChanged(rangeMode);
}
void TraceWindow::toggleLockMode(bool active)
{
bool lockMode = !m_mainView->rootObject()->property("selectionLocked").toBool();
if (active != lockMode) {
m_mainView->rootObject()->setProperty("selectionLocked", QVariant(!active));
m_mainView->rootObject()->setProperty("selectedItem", QVariant(-1));
}
}
void TraceWindow::updateLockButton()
{
bool lockMode = !m_mainView->rootObject()->property("selectionLocked").toBool();
emit lockModeChanged(lockMode);
}
void TraceWindow::setRecording(bool recording)
{
if (recording) {
m_v8DataReady = false;
m_qmlDataReady = false;
}
if (m_plugin)
m_plugin.data()->setRecording(recording);
if (m_v8plugin)
m_v8plugin.data()->setRecording(recording);
}
bool TraceWindow::isRecording() const
{
return m_plugin.data()->isRecording();
}
void TraceWindow::qmlComplete()
{
m_qmlDataReady = true;
if (!m_v8plugin || m_v8plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_v8DataReady) {
m_eventList->complete();
// once complete is sent, reset the flags
m_qmlDataReady = false;
m_v8DataReady = false;
}
}
void TraceWindow::v8Complete()
{
m_v8DataReady = true;
if (!m_plugin || m_plugin.data()->status() != QDeclarativeDebugClient::Enabled || m_qmlDataReady) {
m_eventList->complete();
// once complete is sent, reset the flags
m_v8DataReady = false;
m_qmlDataReady = false;
}
}
void TraceWindow::resizeEvent(QResizeEvent *event)
{
if (m_mainView->rootObject()) {
m_mainView->rootObject()->setProperty("width", QVariant(event->size().width()));
int newHeight = event->size().height() - m_timebar->height() - m_overview->height();
m_mainView->rootObject()->setProperty("candidateHeight", QVariant(newHeight));
}
}
bool MouseWheelResizer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Wheel) {
QWheelEvent *ev = static_cast<QWheelEvent *>(event);
if (ev->modifiers() & Qt::ControlModifier) {
emit mouseWheelMoved(ev->pos().x(), ev->pos().y(), ev->delta());
return true;
}
}
return QObject::eventFilter(obj, event);
}
void TraceWindow::mouseWheelMoved(int x, int y, int delta)
{
Q_UNUSED(y);
if (m_mainView->rootObject()) {
emit wheelZoom(QVariant(x), QVariant(delta));
}
}
void TraceWindow::viewAll()
{
emit globalZoom();
}
bool TraceWindow::hasValidSelection() const
{
if (m_mainView->rootObject()) {
return m_mainView->rootObject()->property("selectionRangeReady").toBool();
}
return false;
}
qint64 TraceWindow::selectionStart() const
{
if (m_mainView->rootObject()) {
return m_mainView->rootObject()->property("selectionRangeStart").toLongLong();
}
return 0;
}
qint64 TraceWindow::selectionEnd() const
{
if (m_mainView->rootObject()) {
return m_mainView->rootObject()->property("selectionRangeEnd").toLongLong();
}
return 0;
}
void TraceWindow::setZoomLevel(int zoomLevel)
{
if (m_currentZoomLevel != zoomLevel && m_mainView->rootObject()) {
qreal newFactor = pow(qreal(zoomLevel) / qreal(sliderTicks), sliderExp);
m_currentZoomLevel = zoomLevel;
emit updateViewZoom(QVariant(newFactor));
}
}
void TraceWindow::updateRange()
{
if (!m_eventList)
return;
qreal duration = m_zoomControl.data()->endTime() - m_zoomControl.data()->startTime();
if (duration <= 0)
return;
if (m_eventList->traceDuration() <= 0)
return;
int newLevel = pow(duration / m_eventList->traceDuration(), 1/sliderExp) * sliderTicks;
if (m_currentZoomLevel != newLevel) {
m_currentZoomLevel = newLevel;
emit zoomLevelChanged(newLevel);
}
}
void TraceWindow::selectNextEvent(int eventId)
{
emit selectNextEventInDisplay(QVariant(eventId));
}
void TraceWindow::updateProfilerState()
{
bool qmlActive = false;
bool v8Active = false;
if (m_plugin)
qmlActive = m_plugin.data()->isEnabled();
if (m_v8plugin)
v8Active = m_v8plugin.data()->isEnabled();
emit profilerStateChanged(qmlActive, v8Active);
}
void TraceWindow::updateToolTip(const QString &text)
{
setToolTip(text);
}
void TraceWindow::updateVerticalScroll(int newPosition)
{
m_mainView->verticalScrollBar()->setValue(newPosition);
}
void TraceWindow::eventListStateChanged()
{
switch (m_eventList->currentState()) {
case QmlProfilerEventList::Empty :
clearDisplay();
break;
case QmlProfilerEventList::AcquiringData :
firstDataReceived();
break;
case QmlProfilerEventList::ProcessingData :
// nothing to be done
break;
case QmlProfilerEventList::Done :
correctTimer();
break;
default:
break;
}
}
void TraceWindow::manageTraceStart(qint64 traceStart)
{
// new trace started
emit clearViewsFromTool();
emit traceStarted(traceStart);
}
void TraceWindow::firstDataReceived()
{
if (m_plugin && m_plugin.data()->isRecording()) {
// serverside recording disabled
m_plugin.data()->setRecordingFromServer(false);
}
}
void TraceWindow::applicationDied()
{
if (m_mainView->rootObject())
m_mainView->rootObject()->setProperty("applicationDied",QVariant(true));
}
} // namespace Internal
} // namespace QmlProfiler

View File

@@ -1,57 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "commandlistener.h"
#include "constants.h"
#include <QTextStream>
CommandListener::CommandListener(QObject *parent)
: QThread(parent)
, m_stopRequested(false)
{
}
void CommandListener::run()
{
QString line;
QTextStream in(stdin, QIODevice::ReadOnly);
do {
line = in.readLine();
line = line.trimmed();
if (!line.isEmpty()) {
emit command(line);
if (line == QLatin1String(Constants::CMD_QUIT)
|| line == QLatin1String(Constants::CMD_QUIT2))
return;
}
} while (!m_stopRequested && !line.isNull());
}

View File

@@ -1,50 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace Constants {
const char CMD_HELP[] ="help";
const char CMD_HELP2[] = "h";
const char CMD_HELP3[] = "?";
const char CMD_RECORD[] ="record";
const char CMD_RECORD2[] ="r";
const char CMD_QUIT[] ="quit";
const char CMD_QUIT2[] = "q";
} // Contants
#endif // CONSTANTS_H

View File

@@ -1,113 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef QMLPROFILERAPPLICATION_H
#define QMLPROFILERAPPLICATION_H
#include <QCoreApplication>
#include <QStringList>
#include <QTimer>
#include <qdeclarativedebugclient.h>
#include <qmlprofilertraceclient.h>
#include <qmlprofilereventlist.h>
#include <qv8profilerclient.h>
QT_FORWARD_DECLARE_CLASS(QProcess)
class QmlProfilerApplication : public QCoreApplication
{
Q_OBJECT
public:
QmlProfilerApplication(int &argc, char **argv);
~QmlProfilerApplication();
bool parseArguments();
void printUsage();
int exec();
public slots:
void userCommand(const QString &command);
private slots:
void run();
void tryToConnect();
void connected();
void connectionStateChanged(QAbstractSocket::SocketState state);
void connectionError(QAbstractSocket::SocketError error);
void processHasOutput();
void processFinished();
void traceClientEnabled();
void profilerClientEnabled();
void traceFinished();
void recordingChanged();
void print(const QString &line);
void logError(const QString &error);
void logStatus(const QString &status);
void qmlComplete();
void v8Complete();
private:
void printCommands();
QString traceFileName() const;
enum ApplicationMode {
LaunchMode,
AttachMode
} m_runMode;
// LaunchMode
QString m_programPath;
QStringList m_programArguments;
QProcess *m_process;
QString m_tracePrefix;
QString m_hostName;
quint16 m_port;
bool m_verbose;
bool m_quitAfterSave;
QmlJsDebugClient::QDeclarativeDebugConnection m_connection;
QmlJsDebugClient::QmlProfilerTraceClient m_qmlProfilerClient;
QmlJsDebugClient::QV8ProfilerClient m_v8profilerClient;
QmlJsDebugClient::QmlProfilerEventList m_eventList;
QTimer m_connectTimer;
uint m_connectionAttempts;
bool m_qmlDataReady;
bool m_v8DataReady;
};
#endif // QMLPROFILERAPPLICATION_H

View File

@@ -1,28 +0,0 @@
QT = core
include(../../../qtcreator.pri)
include(../../rpath.pri)
TEMPLATE = app
TARGET = qmlprofiler
DESTDIR = $$IDE_BIN_PATH
CONFIG += console
CONFIG -= app_bundle
include(../../shared/symbianutils/symbianutils.pri)
include(../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)
INCLUDEPATH += ../../libs/qmljsdebugclient
SOURCES += main.cpp \
qmlprofilerapplication.cpp \
commandlistener.cpp
HEADERS += \
qmlprofilerapplication.h \
commandlistener.h \
constants.h
target.path=/bin
INSTALLS+=target

View File

@@ -1,7 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = qtpromaker \
qmlprofilertool \
qmlpuppet
win32 {