Fix backward compatibility issue with QmlProfiler

Previous implementation uses MaxMessage and MaxRangeType constants to
specify events with undefined message or range type. This causes
backwards compatibility issue if new message or range types are
added, because those constants are also written to files when saving
profiler traces.

Add UndefinedMessage and UndefinedRangeType constants and use those
instead of the MaxMessage and MaxRangeType constants. This doesn't fix
opening old traces, but the same problem won't happend again with new
traces.

Also update profiler autotests with fixed data.

Task-number: QTCREATORBUG-28146
Change-Id: Ief003d39f871dd1ff2cc908e6a4d4b4678fd0868
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Antti Määttä
2022-09-19 15:34:52 +03:00
parent e8ebd8e497
commit 0f49728c32
24 changed files with 60 additions and 58 deletions

View File

@@ -32,7 +32,7 @@ namespace Internal {
DebugMessagesModel::DebugMessagesModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, DebugMessage, MaximumRangeType, ProfileDebugMessages, parent),
QmlProfilerTimelineModel(manager, DebugMessage, UndefinedRangeType, ProfileDebugMessages, parent),
m_maximumMsgType(-1)
{
}

View File

@@ -38,7 +38,7 @@ namespace Internal {
InputEventsModel::InputEventsModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, Event, MaximumRangeType, ProfileInputEvents, parent),
QmlProfilerTimelineModel(manager, Event, UndefinedRangeType, ProfileInputEvents, parent),
m_keyTypeId(-1), m_mouseTypeId(-1)
{
}

View File

@@ -34,7 +34,7 @@ namespace Internal {
MemoryUsageModel::MemoryUsageModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, MemoryAllocation, MaximumRangeType, ProfileMemory, parent)
QmlProfilerTimelineModel(manager, MemoryAllocation, UndefinedRangeType, ProfileMemory, parent)
{
// Register additional features. The base class already registers the main feature.
// Don't register initializer, finalizer, or clearer as the base class has done so already.
@@ -142,7 +142,7 @@ QVariantMap MemoryUsageModel::details(int index) const
void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
{
if (type.message() != MemoryAllocation) {
if (type.rangeType() != MaximumRangeType) {
if (type.rangeType() != UndefinedRangeType) {
m_continuation = ContinueNothing;
if (event.rangeStage() == RangeStart)
m_rangeStack.push(RangeStackFrame(event.typeIndex(), event.timestamp()));

View File

@@ -34,7 +34,7 @@ namespace Internal {
PixmapCacheModel::PixmapCacheModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, PixmapCacheEvent, MaximumRangeType, ProfilePixmapCache,
QmlProfilerTimelineModel(manager, PixmapCacheEvent, UndefinedRangeType, ProfilePixmapCache,
parent)
{
}

View File

@@ -39,7 +39,7 @@ class QmlEventType : public Timeline::TraceEventType {
public:
static const qint32 staticClassId = 0x716d6c74; // 'qmlt';
QmlEventType(Message message = MaximumMessage, RangeType rangeType = MaximumRangeType,
QmlEventType(Message message = UndefinedMessage, RangeType rangeType = UndefinedRangeType,
int detailType = -1, const QmlEventLocation &location = QmlEventLocation(),
const QString &data = QString(), const QString &displayName = QString());

View File

@@ -42,7 +42,7 @@ namespace Internal {
QmlProfilerAnimationsModel::QmlProfilerAnimationsModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, Event, MaximumRangeType, ProfileAnimations, parent)
QmlProfilerTimelineModel(manager, Event, UndefinedRangeType, ProfileAnimations, parent)
{
m_minNextStartTimes[0] = m_minNextStartTimes[1] = 0;
}

View File

@@ -30,7 +30,8 @@
namespace QmlProfiler {
enum Message {
Event,
UndefinedMessage = 0xff,
Event = 0,
RangeStart,
RangeData,
RangeLocation,
@@ -72,7 +73,8 @@ enum Quick3DEventType {
};
enum RangeType {
Painting, // old Qt4 paint events
UndefinedRangeType = 0xff,
Painting = 0, // old Qt4 paint events
Compiling,
Creating,
Binding,

View File

@@ -393,7 +393,7 @@ QmlProfilerModelManager::rangeFilter(qint64 rangeStart, qint64 rangeEnd) const
// Double-check if rangeStart has been crossed. Some versions of Qt send dirty data.
qint64 adjustedTimestamp = event.timestamp();
if (event.timestamp() < rangeStart && !crossedRangeStart) {
if (type.rangeType() != MaximumRangeType) {
if (type.rangeType() != UndefinedRangeType) {
if (event.rangeStage() == RangeStart)
stack.push(event);
else if (event.rangeStage() == RangeEnd && !stack.isEmpty())
@@ -414,7 +414,7 @@ QmlProfilerModelManager::rangeFilter(qint64 rangeStart, qint64 rangeEnd) const
crossedRangeStart = true;
}
if (event.timestamp() > rangeEnd) {
if (type.rangeType() != MaximumRangeType) {
if (type.rangeType() != UndefinedRangeType) {
if (event.rangeStage() == RangeEnd) {
if (stack.isEmpty()) {
QmlEvent endEvent(event);

View File

@@ -44,7 +44,7 @@ namespace Internal {
QmlProfilerRangeModel::QmlProfilerRangeModel(QmlProfilerModelManager *manager, RangeType range,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, MaximumMessage, range, featureFromRangeType(range), parent)
QmlProfilerTimelineModel(manager, UndefinedMessage, range, featureFromRangeType(range), parent)
{
m_expandedRowTypes << -1;
}

View File

@@ -170,7 +170,7 @@ void QmlProfilerTraceClientPrivate::processCurrentEvent()
// all ranges are perfectly nested. This is why we can defer the type resolution until either
// the range ends or a child range starts. With only the information in RangeStart we wouldn't
// be able to uniquely identify the event type.
Message rangeStage = currentEvent.type.rangeType() == MaximumRangeType ?
Message rangeStage = currentEvent.type.rangeType() == UndefinedRangeType ?
currentEvent.type.message() : currentEvent.event.rangeStage();
switch (rangeStage) {
case RangeStart:
@@ -333,7 +333,7 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features)
d->currentEvent.event.setTimestamp(context.timestamp > 0 ? context.timestamp : 0);
d->currentEvent.event.setTypeIndex(-1);
d->currentEvent.event.setString(text);
d->currentEvent.type = QmlEventType(DebugMessage, MaximumRangeType, type,
d->currentEvent.type = QmlEventType(DebugMessage, UndefinedRangeType, type,
QmlEventLocation(context.file, context.line, 1));
d->currentEvent.serverTypeId = 0;
d->processCurrentEvent();

View File

@@ -80,7 +80,7 @@ Q_STATIC_ASSERT(sizeof(MESSAGE_STRINGS) == MaximumMessage * sizeof(const char *)
static QPair<Message, RangeType> qmlTypeAsEnum(const QString &typeString)
{
QPair<Message, RangeType> ret(MaximumMessage, MaximumRangeType);
QPair<Message, RangeType> ret(UndefinedMessage, UndefinedRangeType);
for (int i = 0; i < MaximumMessage; ++i) {
if (typeString == _(MESSAGE_STRINGS[i])) {
@@ -96,7 +96,7 @@ static QPair<Message, RangeType> qmlTypeAsEnum(const QString &typeString)
}
}
if (ret.first == MaximumMessage && ret.second == MaximumRangeType) {
if (ret.first == UndefinedMessage && ret.second == UndefinedRangeType) {
bool isNumber = false;
int type = typeString.toUInt(&isNumber);
if (isNumber && type < MaximumRangeType)
@@ -309,7 +309,7 @@ void QmlProfilerTraceFile::loadEventTypes(QXmlStreamReader &stream)
int typeIndex = -1;
QPair<Message, RangeType> messageAndRange(MaximumMessage, MaximumRangeType);
QPair<Message, RangeType> messageAndRange(UndefinedMessage, UndefinedRangeType);
int detailType = -1;
QString displayName;
QString data;
@@ -317,7 +317,7 @@ void QmlProfilerTraceFile::loadEventTypes(QXmlStreamReader &stream)
int line = 0, column = 0;
auto clearType = [&](){
messageAndRange = QPair<Message, RangeType>(MaximumMessage, MaximumRangeType);
messageAndRange = QPair<Message, RangeType>(UndefinedMessage, UndefinedRangeType);
detailType = -1;
displayName.clear();
data.clear();
@@ -389,7 +389,7 @@ void QmlProfilerTraceFile::loadEventTypes(QXmlStreamReader &stream)
// confusing), even though they clearly aren't ranges. Convert that to something
// sane here.
if (detailType == 4) {
messageAndRange = QPair<Message, RangeType>(Event, MaximumRangeType);
messageAndRange = QPair<Message, RangeType>(Event, UndefinedRangeType);
detailType = AnimationFrame;
}
}
@@ -695,13 +695,13 @@ void QmlProfilerTraceFile::saveQtd(QIODevice *device)
QStack<QmlEvent> stack;
qint64 lastProgressTimestamp = traceStart();
modelManager()->replayQmlEvents([&](const QmlEvent &event, const QmlEventType &type) {
if (type.rangeType() != MaximumRangeType && event.rangeStage() == RangeStart) {
if (type.rangeType() != UndefinedRangeType && event.rangeStage() == RangeStart) {
stack.push(event);
return;
}
stream.writeStartElement(_("range"));
if (type.rangeType() != MaximumRangeType && event.rangeStage() == RangeEnd) {
if (type.rangeType() != UndefinedRangeType && event.rangeStage() == RangeEnd) {
QmlEvent start = stack.pop();
stream.writeAttribute(_("startTime"), QString::number(start.timestamp()));
stream.writeAttribute(_("duration"),

View File

@@ -36,10 +36,10 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
stream >> time >> messageType;
if (messageType < 0 || messageType > MaximumMessage)
messageType = MaximumMessage;
if (messageType < 0 || messageType >= MaximumMessage)
messageType = UndefinedMessage;
RangeType rangeType = MaximumRangeType;
RangeType rangeType = UndefinedRangeType;
if (!stream.atEnd()) {
stream >> subtype;
if (subtype >= 0 && subtype < MaximumRangeType)
@@ -54,7 +54,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
switch (messageType) {
case Event: {
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
switch (subtype) {
case StartTrace:
case EndTrace: {
@@ -98,7 +98,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
break;
}
case Complete: {
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
break;
}
case SceneGraphFrame: {
@@ -110,7 +110,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
params.push_back(param);
}
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
event.event.setNumbers<QVarLengthArray<qint64>, qint64>(params);
break;
}
@@ -125,7 +125,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
refcount = 1;
}
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype,
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype,
QmlEventLocation(filename, 0, 0));
event.event.setNumbers<qint32>({width, height, refcount});
break;
@@ -134,7 +134,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
qint64 delta;
stream >> delta;
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
event.event.setNumbers<qint64>({delta});
break;
}
@@ -147,7 +147,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
// otherwise it's the old binding type of 4 bytes
}
event.type = QmlEventType(MaximumMessage, rangeType, -1);
event.type = QmlEventType(UndefinedMessage, rangeType, -1);
event.event.setRangeStage(RangeStart);
break;
}
@@ -155,7 +155,7 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
QString data;
stream >> data;
event.type = QmlEventType(MaximumMessage, rangeType, -1, QmlEventLocation(), data);
event.type = QmlEventType(UndefinedMessage, rangeType, -1, QmlEventLocation(), data);
event.event.setRangeStage(RangeData);
if (!stream.atEnd())
stream >> event.serverTypeId;
@@ -173,13 +173,13 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
stream >> event.serverTypeId;
}
event.type = QmlEventType(MaximumMessage, rangeType, -1,
event.type = QmlEventType(UndefinedMessage, rangeType, -1,
QmlEventLocation(filename, line, column));
event.event.setRangeStage(RangeLocation);
break;
}
case RangeEnd: {
event.type = QmlEventType(MaximumMessage, rangeType, -1);
event.type = QmlEventType(UndefinedMessage, rangeType, -1);
event.event.setRangeStage(RangeEnd);
break;
}
@@ -192,13 +192,13 @@ QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event)
stream >> param;
params.push_back(param);
}
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
event.event.setNumbers<QVarLengthArray<qint64>, qint64>(params);
break;
}
default:
event.event.setNumbers<char>({});
event.type = QmlEventType(static_cast<Message>(messageType), MaximumRangeType, subtype);
event.type = QmlEventType(static_cast<Message>(messageType), UndefinedRangeType, subtype);
break;
}

View File

@@ -33,7 +33,7 @@ namespace Internal {
Quick3DModel::Quick3DModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, Quick3DEvent, MaximumRangeType, ProfileQuick3D, parent),
QmlProfilerTimelineModel(manager, Quick3DEvent, UndefinedRangeType, ProfileQuick3D, parent),
m_maximumMsgType(-1)
{
}

View File

@@ -77,7 +77,7 @@ Q_STATIC_ASSERT(sizeof(StageLabels) ==
SceneGraphTimelineModel::SceneGraphTimelineModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, SceneGraphFrame, MaximumRangeType, ProfileSceneGraph, parent)
QmlProfilerTimelineModel(manager, SceneGraphFrame, UndefinedRangeType, ProfileSceneGraph, parent)
{
}

View File

@@ -45,7 +45,7 @@ void DebugMessagesModelTest::initTestCase()
QmlEvent event;
event.setTimestamp(i);
event.setString(QString::fromLatin1("message %1").arg(i));
QmlEventType type(DebugMessage, MaximumRangeType, i % (QtMsgType::QtInfoMsg + 1),
QmlEventType type(DebugMessage, UndefinedRangeType, i % (QtMsgType::QtInfoMsg + 1),
QmlEventLocation("somefile.js", i, 10 - i));
event.setTypeIndex(manager.numEventTypes());
manager.appendEventType(std::move(type));

View File

@@ -55,7 +55,7 @@ int FlameGraphModelTest::generateData(QmlProfilerModelManager *manager,
QmlEvent event;
if (i < 5) {
typeIndex = manager->appendEventType(
QmlEventType(MaximumMessage,
QmlEventType(UndefinedMessage,
static_cast<RangeType>(static_cast<int>(Javascript) - i), -1,
QmlEventLocation("somefile.js", i, 20 - i),
QString("funcfunc")));

View File

@@ -41,8 +41,8 @@ static InputEventType inputType(int i)
InputEventsModelTest::InputEventsModelTest(QObject *parent) :
QObject(parent), model(&manager, &aggregator)
{
keyTypeId = manager.appendEventType(QmlEventType(Event, MaximumRangeType, Key));
mouseTypeId = manager.appendEventType(QmlEventType(Event, MaximumRangeType, Mouse));
keyTypeId = manager.appendEventType(QmlEventType(Event, UndefinedRangeType, Key));
mouseTypeId = manager.appendEventType(QmlEventType(Event, UndefinedRangeType, Mouse));
}
void InputEventsModelTest::initTestCase()

View File

@@ -41,11 +41,11 @@ void MemoryUsageModelTest::initTestCase()
heapPageTypeId = manager.numEventTypes();
manager.appendEventType(QmlEventType(MemoryAllocation, MaximumRangeType, HeapPage));
manager.appendEventType(QmlEventType(MemoryAllocation, UndefinedRangeType, HeapPage));
smallItemTypeId = manager.numEventTypes();
manager.appendEventType(QmlEventType(MemoryAllocation, MaximumRangeType, SmallItem));
manager.appendEventType(QmlEventType(MemoryAllocation, UndefinedRangeType, SmallItem));
largeItemTypeId = manager.numEventTypes();
manager.appendEventType(QmlEventType(MemoryAllocation, MaximumRangeType, LargeItem));
manager.appendEventType(QmlEventType(MemoryAllocation, UndefinedRangeType, LargeItem));
auto addMemoryEvents = [&]() {
QmlEvent event;
@@ -74,7 +74,7 @@ void MemoryUsageModelTest::initTestCase()
addMemoryEvents();
rangeTypeId = manager.numEventTypes();
manager.appendEventType(QmlEventType(MaximumMessage, Javascript, -1,
manager.appendEventType(QmlEventType(UndefinedMessage, Javascript, -1,
QmlEventLocation(QString("somefile.js"), 10, 20),
QString("funcfunc")));

View File

@@ -43,7 +43,7 @@ void PixmapCacheModelTest::initTestCase()
for (int i = 0; i < MaximumPixmapEventType; ++i) {
eventTypeIndices[i] = manager.numEventTypes();
manager.appendEventType(QmlEventType(PixmapCacheEvent, MaximumRangeType, i,
manager.appendEventType(QmlEventType(PixmapCacheEvent, UndefinedRangeType, i,
QmlEventLocation("dings.png", 0, 0)));
}
@@ -58,7 +58,7 @@ void PixmapCacheModelTest::initTestCase()
for (int i = 0; i < MaximumPixmapEventType; ++i) {
eventTypeIndices[i + MaximumPixmapEventType] = manager.numEventTypes();
manager.appendEventType(QmlEventType(PixmapCacheEvent, MaximumRangeType, i,
manager.appendEventType(QmlEventType(PixmapCacheEvent, UndefinedRangeType, i,
QmlEventLocation("blah.png", 0, 0)));
}

View File

@@ -37,8 +37,8 @@ QmlEventTypeTest::QmlEventTypeTest(QObject *parent) : QObject(parent)
void QmlEventTypeTest::testAccessors()
{
QmlEventType type;
QCOMPARE(type.message(), MaximumMessage);
QCOMPARE(type.rangeType(), MaximumRangeType);
QCOMPARE(type.message(), UndefinedMessage);
QCOMPARE(type.rangeType(), UndefinedMessage);
QCOMPARE(type.detailType(), -1);
QVERIFY(!type.location().isValid());
QVERIFY(type.data().isEmpty());
@@ -56,9 +56,9 @@ void QmlEventTypeTest::testAccessors()
type.setDisplayName("disdis");
QCOMPARE(type.displayName(), QString("disdis"));
QmlEventType type2(MaximumMessage, Javascript, 12, QmlEventLocation("lala.js", 2, 3), "nehhh",
QmlEventType type2(UndefinedMessage, Javascript, 12, QmlEventLocation("lala.js", 2, 3), "nehhh",
"brbr");
QCOMPARE(type2.message(), MaximumMessage);
QCOMPARE(type2.message(), UndefinedMessage);
QCOMPARE(type2.rangeType(), Javascript);
QCOMPARE(type2.detailType(), 12);
QCOMPARE(type2.location(), QmlEventLocation("lala.js", 2, 3));
@@ -107,13 +107,13 @@ void QmlEventTypeTest::testFeature()
for (int i = 0; i < MaximumMessage; ++i) {
for (int j = 0; j < MaximumEventType; ++j) {
QmlEventType type(static_cast<Message>(i), MaximumRangeType, j);
QmlEventType type(static_cast<Message>(i), UndefinedRangeType, j);
QCOMPARE(type.feature(), features[i][j]);
}
}
for (int i = 0; i < MaximumRangeType; ++i) {
QmlEventType type(MaximumMessage, static_cast<RangeType>(i));
QmlEventType type(UndefinedMessage, static_cast<RangeType>(i));
QCOMPARE(static_cast<ProfileFeature>(type.feature()),
featureFromRangeType(static_cast<RangeType>(i)));
}
@@ -121,7 +121,7 @@ void QmlEventTypeTest::testFeature()
void QmlEventTypeTest::testStreamOps()
{
QmlEventType type(MaximumMessage, Javascript, -1, QmlEventLocation("socken.js", 12, 13),
QmlEventType type(UndefinedMessage, Javascript, -1, QmlEventLocation("socken.js", 12, 13),
"lalala", "lelele");
QBuffer wbuffer;

View File

@@ -46,7 +46,7 @@ void QmlProfilerAnimationsModelTest::initTestCase()
QmlEvent event;
event.setTypeIndex(manager.appendEventType(
QmlEventType(Event, MaximumRangeType, AnimationFrame)));
QmlEventType(Event, UndefinedRangeType, AnimationFrame)));
for (int i = 0; i < 10; ++i) {
event.setTimestamp(i);

View File

@@ -49,7 +49,7 @@ DummyModel::DummyModel(QmlProfilerModelManager *manager,
void DummyModel::loadData()
{
QmlEventType type(MaximumMessage, Binding);
QmlEventType type(UndefinedMessage, Binding);
const int typeIndex = modelManager()->appendEventType(QmlEventType(type));
QCOMPARE(typeIndex, 0);

View File

@@ -77,8 +77,8 @@ void QmlProfilerTraceClientTest::testMessageReceived()
modelManager.replayQmlEvents([&](const QmlEvent &event, const QmlEventType &type) {
qint64 timestamp;
qint32 message;
qint32 rangeType;
quint8 message;
quint8 rangeType;
checkStream >> timestamp >> message >> rangeType;
QCOMPARE(event.timestamp(), timestamp);
QCOMPARE(type.message(), static_cast<Message>(message));