Tracing: Make sure we don't cast between different kinds of events

Add a classId to TraceEvent and TraceEventType and add is() and as()
methods that check for it.

Change-Id: I76fe1df624516b36db90d57d4788b17e0b690726
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ulf Hermann
2018-05-07 10:50:58 +02:00
parent c73c86e1a3
commit 37bcbf7575
9 changed files with 106 additions and 18 deletions

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
namespace Timeline {
template<class Base>
class SafeCastable
{
public:
template<class Derived>
bool is() const
{
return static_cast<const Base *>(this)->classId() == Derived::staticClassId;
}
template<class Derived>
Derived &asRef()
{
Q_ASSERT(is<Derived>());
return static_cast<Derived &>(*this);
}
template<class Derived>
const Derived &asConstRef() const
{
Q_ASSERT(is<Derived>());
return static_cast<const Derived &>(*this);
}
template<class Derived>
Derived &&asRvalueRef()
{
Q_ASSERT(is<Derived>());
return static_cast<Derived &&>(*this);
}
};
} // namespace Timeline

View File

@@ -26,13 +26,14 @@
#pragma once
#include "tracing_global.h"
#include "safecastable.h"
#include <QHash>
#include <QMetaType>
namespace Timeline {
class TraceEvent
class TraceEvent : public SafeCastable<TraceEvent>
{
public:
qint64 timestamp() const { return m_timestamp; }
@@ -43,9 +44,11 @@ public:
bool isValid() const { return m_typeIndex != -1; }
qint32 classId() const { return m_classId; }
protected:
TraceEvent(qint64 timestamp = -1, qint32 typeIndex = -1)
: m_timestamp(timestamp), m_typeIndex(typeIndex)
TraceEvent(qint32 classId, qint64 timestamp = -1, qint32 typeIndex = -1)
: m_timestamp(timestamp), m_typeIndex(typeIndex), m_classId(classId)
{}
TraceEvent(const TraceEvent &) = default;
@@ -56,6 +59,7 @@ protected:
private:
qint64 m_timestamp;
qint32 m_typeIndex;
qint32 m_classId;
};
} // namespace Timeline

View File

@@ -26,6 +26,7 @@
#pragma once
#include "tracing_global.h"
#include "safecastable.h"
#include <QHash>
#include <QMetaType>
@@ -33,7 +34,7 @@
namespace Timeline {
class TraceEventType
class TraceEventType : public SafeCastable<TraceEventType>
{
public:
const QString &displayName() const { return m_displayName; }
@@ -42,9 +43,11 @@ public:
quint8 feature() const { return m_feature; }
void setFeature(quint8 feature) { m_feature = feature; }
qint32 classId() const { return m_classId; }
protected:
TraceEventType(quint8 feature = 255, const QString &displayName = QString())
: m_displayName(displayName), m_feature(feature)
TraceEventType(qint32 classId, quint8 feature = 255, const QString &displayName = QString())
: m_displayName(displayName), m_classId(classId), m_feature(feature)
{}
TraceEventType(const TraceEventType &) = default;
@@ -54,6 +57,7 @@ protected:
private:
QString m_displayName;
qint32 m_classId;
quint8 m_feature;
};

View File

@@ -25,6 +25,7 @@ SOURCES += \
HEADERS += \
$$PWD/flamegraph.h \
$$PWD/flamegraphattached.h \
$$PWD/safecastable.h \
$$PWD/tracing_global.h \
$$PWD/timelinemodel.h \
$$PWD/timelinemodel_p.h \

View File

@@ -17,6 +17,7 @@ Project {
"README",
"flamegraph.cpp", "flamegraph.h",
"flamegraphattached.h",
"safecastable.h",
"timelineabstractrenderer.cpp", "timelineabstractrenderer.h",
"timelineabstractrenderer_p.h",
"timelineformattime.cpp", "timelineformattime.h",

View File

@@ -39,24 +39,26 @@
namespace QmlProfiler {
struct QmlEvent : public Timeline::TraceEvent {
QmlEvent() : m_dataType(Inline8Bit), m_dataLength(0) {}
static const qint32 staticClassId = 0x716d6c65; // 'qmle';
QmlEvent() : TraceEvent(staticClassId), m_dataType(Inline8Bit), m_dataLength(0) {}
template<typename Number>
QmlEvent(qint64 timestamp, int typeIndex, std::initializer_list<Number> list)
: TraceEvent(timestamp, typeIndex)
: TraceEvent(staticClassId, timestamp, typeIndex)
{
assignNumbers<std::initializer_list<Number>, Number>(list);
}
QmlEvent(qint64 timestamp, int typeIndex, const QString &data)
: TraceEvent(timestamp, typeIndex)
: TraceEvent(staticClassId, timestamp, typeIndex)
{
assignNumbers<QByteArray, qint8>(data.toUtf8());
}
template<typename Number>
QmlEvent(qint64 timestamp, int typeIndex, const QVector<Number> &data)
: TraceEvent(timestamp, typeIndex)
: TraceEvent(staticClassId, timestamp, typeIndex)
{
assignNumbers<QVector<Number>, Number>(data);
}

View File

@@ -79,7 +79,7 @@ QDataStream &operator<<(QDataStream &stream, const QmlEventType &type)
QmlEventType::QmlEventType(Message message, RangeType rangeType, int detailType,
const QmlEventLocation &location, const QString &data,
const QString displayName) :
TraceEventType(qmlFeatureFromType(message, rangeType, detailType)),
TraceEventType(staticClassId, qmlFeatureFromType(message, rangeType, detailType)),
m_data(data), m_location(location), m_message(message),
m_rangeType(rangeType), m_detailType(detailType)
{

View File

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

View File

@@ -148,8 +148,9 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
{
const TraceEventLoader traceEventLoader = eventLoader ? [eventLoader](
const Timeline::TraceEvent &event, const Timeline::TraceEventType &type) {
return eventLoader(static_cast<const QmlEvent &>(event),
static_cast<const QmlEventType &>(type));
QTC_ASSERT(event.is<QmlEvent>(), return);
QTC_ASSERT(type.is<QmlEventType>(), return);
eventLoader(event.asConstRef<QmlEvent>(), type.asConstRef<QmlEventType>());
} : TraceEventLoader();
Timeline::TimelineTraceManager::registerFeatures(features, traceEventLoader, initializer,
@@ -158,7 +159,10 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const
{
return static_cast<const QmlEventType &>(TimelineTraceManager::eventType(typeId));
static const QmlEventType invalid;
const Timeline::TraceEventType &type = TimelineTraceManager::eventType(typeId);
QTC_ASSERT(type.is<QmlEventType>(), return invalid);
return type.asConstRef<QmlEventType>();
}
void QmlProfilerModelManager::replayEvents(TraceEventLoader loader, Initializer initializer,
@@ -190,7 +194,8 @@ void QmlProfilerModelManager::replayQmlEvents(QmlEventLoader loader,
if (future.isCanceled())
return false;
loader(static_cast<QmlEvent &&>(event), eventType(event.typeIndex()));
QTC_ASSERT(event.is<QmlEvent>(), return false);
loader(event.asRvalueRef<QmlEvent>(), eventType(event.typeIndex()));
return true;
});
@@ -462,13 +467,19 @@ void QmlProfilerEventTypeStorage::set(int typeId, Timeline::TraceEventType &&typ
const size_t index = static_cast<size_t>(typeId);
if (m_types.size() <= index)
m_types.resize(index + 1);
m_types[index] = std::move(static_cast<QmlEventType &&>(type));
QTC_ASSERT(type.is<QmlEventType>(), return);
m_types[index] = std::move(type.asRvalueRef<QmlEventType>());
}
int QmlProfilerEventTypeStorage::append(Timeline::TraceEventType &&type)
{
const size_t index = m_types.size();
m_types.push_back(std::move(static_cast<QmlEventType &&>(type)));
if (type.is<QmlEventType>()) {
m_types.push_back(std::move(type.asRvalueRef<QmlEventType>()));
} else {
QTC_CHECK(false);
m_types.push_back(QmlEventType());
}
QTC_ASSERT(index <= std::numeric_limits<int>::max(), return std::numeric_limits<int>::max());
return static_cast<int>(index);
}
@@ -495,7 +506,8 @@ QmlProfilerEventStorage::QmlProfilerEventStorage(
int QmlProfilerEventStorage::append(Timeline::TraceEvent &&event)
{
m_file.append(std::move(static_cast<QmlEvent &&>(event)));
QTC_ASSERT(event.is<QmlEvent>(), return m_size);
m_file.append(std::move(event.asRvalueRef<QmlEvent>()));
return m_size++;
}