forked from qt-creator/qt-creator
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:
62
src/libs/tracing/safecastable.h
Normal file
62
src/libs/tracing/safecastable.h
Normal 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
|
@@ -26,13 +26,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tracing_global.h"
|
#include "tracing_global.h"
|
||||||
|
#include "safecastable.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
namespace Timeline {
|
namespace Timeline {
|
||||||
|
|
||||||
class TraceEvent
|
class TraceEvent : public SafeCastable<TraceEvent>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
qint64 timestamp() const { return m_timestamp; }
|
qint64 timestamp() const { return m_timestamp; }
|
||||||
@@ -43,9 +44,11 @@ public:
|
|||||||
|
|
||||||
bool isValid() const { return m_typeIndex != -1; }
|
bool isValid() const { return m_typeIndex != -1; }
|
||||||
|
|
||||||
|
qint32 classId() const { return m_classId; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TraceEvent(qint64 timestamp = -1, qint32 typeIndex = -1)
|
TraceEvent(qint32 classId, qint64 timestamp = -1, qint32 typeIndex = -1)
|
||||||
: m_timestamp(timestamp), m_typeIndex(typeIndex)
|
: m_timestamp(timestamp), m_typeIndex(typeIndex), m_classId(classId)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TraceEvent(const TraceEvent &) = default;
|
TraceEvent(const TraceEvent &) = default;
|
||||||
@@ -56,6 +59,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
qint64 m_timestamp;
|
qint64 m_timestamp;
|
||||||
qint32 m_typeIndex;
|
qint32 m_typeIndex;
|
||||||
|
qint32 m_classId;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Timeline
|
} // namespace Timeline
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "tracing_global.h"
|
#include "tracing_global.h"
|
||||||
|
#include "safecastable.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
|
|
||||||
namespace Timeline {
|
namespace Timeline {
|
||||||
|
|
||||||
class TraceEventType
|
class TraceEventType : public SafeCastable<TraceEventType>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const QString &displayName() const { return m_displayName; }
|
const QString &displayName() const { return m_displayName; }
|
||||||
@@ -42,9 +43,11 @@ public:
|
|||||||
quint8 feature() const { return m_feature; }
|
quint8 feature() const { return m_feature; }
|
||||||
void setFeature(quint8 feature) { m_feature = feature; }
|
void setFeature(quint8 feature) { m_feature = feature; }
|
||||||
|
|
||||||
|
qint32 classId() const { return m_classId; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TraceEventType(quint8 feature = 255, const QString &displayName = QString())
|
TraceEventType(qint32 classId, quint8 feature = 255, const QString &displayName = QString())
|
||||||
: m_displayName(displayName), m_feature(feature)
|
: m_displayName(displayName), m_classId(classId), m_feature(feature)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TraceEventType(const TraceEventType &) = default;
|
TraceEventType(const TraceEventType &) = default;
|
||||||
@@ -54,6 +57,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_displayName;
|
QString m_displayName;
|
||||||
|
qint32 m_classId;
|
||||||
quint8 m_feature;
|
quint8 m_feature;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ SOURCES += \
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/flamegraph.h \
|
$$PWD/flamegraph.h \
|
||||||
$$PWD/flamegraphattached.h \
|
$$PWD/flamegraphattached.h \
|
||||||
|
$$PWD/safecastable.h \
|
||||||
$$PWD/tracing_global.h \
|
$$PWD/tracing_global.h \
|
||||||
$$PWD/timelinemodel.h \
|
$$PWD/timelinemodel.h \
|
||||||
$$PWD/timelinemodel_p.h \
|
$$PWD/timelinemodel_p.h \
|
||||||
|
@@ -17,6 +17,7 @@ Project {
|
|||||||
"README",
|
"README",
|
||||||
"flamegraph.cpp", "flamegraph.h",
|
"flamegraph.cpp", "flamegraph.h",
|
||||||
"flamegraphattached.h",
|
"flamegraphattached.h",
|
||||||
|
"safecastable.h",
|
||||||
"timelineabstractrenderer.cpp", "timelineabstractrenderer.h",
|
"timelineabstractrenderer.cpp", "timelineabstractrenderer.h",
|
||||||
"timelineabstractrenderer_p.h",
|
"timelineabstractrenderer_p.h",
|
||||||
"timelineformattime.cpp", "timelineformattime.h",
|
"timelineformattime.cpp", "timelineformattime.h",
|
||||||
|
@@ -39,24 +39,26 @@
|
|||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
|
|
||||||
struct QmlEvent : public Timeline::TraceEvent {
|
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>
|
template<typename Number>
|
||||||
QmlEvent(qint64 timestamp, int typeIndex, std::initializer_list<Number> list)
|
QmlEvent(qint64 timestamp, int typeIndex, std::initializer_list<Number> list)
|
||||||
: TraceEvent(timestamp, typeIndex)
|
: TraceEvent(staticClassId, timestamp, typeIndex)
|
||||||
{
|
{
|
||||||
assignNumbers<std::initializer_list<Number>, Number>(list);
|
assignNumbers<std::initializer_list<Number>, Number>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlEvent(qint64 timestamp, int typeIndex, const QString &data)
|
QmlEvent(qint64 timestamp, int typeIndex, const QString &data)
|
||||||
: TraceEvent(timestamp, typeIndex)
|
: TraceEvent(staticClassId, timestamp, typeIndex)
|
||||||
{
|
{
|
||||||
assignNumbers<QByteArray, qint8>(data.toUtf8());
|
assignNumbers<QByteArray, qint8>(data.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Number>
|
template<typename Number>
|
||||||
QmlEvent(qint64 timestamp, int typeIndex, const QVector<Number> &data)
|
QmlEvent(qint64 timestamp, int typeIndex, const QVector<Number> &data)
|
||||||
: TraceEvent(timestamp, typeIndex)
|
: TraceEvent(staticClassId, timestamp, typeIndex)
|
||||||
{
|
{
|
||||||
assignNumbers<QVector<Number>, Number>(data);
|
assignNumbers<QVector<Number>, Number>(data);
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ QDataStream &operator<<(QDataStream &stream, const QmlEventType &type)
|
|||||||
QmlEventType::QmlEventType(Message message, RangeType rangeType, int detailType,
|
QmlEventType::QmlEventType(Message message, RangeType rangeType, int detailType,
|
||||||
const QmlEventLocation &location, const QString &data,
|
const QmlEventLocation &location, const QString &data,
|
||||||
const QString displayName) :
|
const QString displayName) :
|
||||||
TraceEventType(qmlFeatureFromType(message, rangeType, detailType)),
|
TraceEventType(staticClassId, qmlFeatureFromType(message, rangeType, detailType)),
|
||||||
m_data(data), m_location(location), m_message(message),
|
m_data(data), m_location(location), m_message(message),
|
||||||
m_rangeType(rangeType), m_detailType(detailType)
|
m_rangeType(rangeType), m_detailType(detailType)
|
||||||
{
|
{
|
||||||
|
@@ -37,6 +37,8 @@ namespace QmlProfiler {
|
|||||||
|
|
||||||
class QmlEventType : public Timeline::TraceEventType {
|
class QmlEventType : public Timeline::TraceEventType {
|
||||||
public:
|
public:
|
||||||
|
static const qint32 staticClassId = 0x716d6c74; // 'qmlt';
|
||||||
|
|
||||||
QmlEventType(Message message = MaximumMessage, RangeType rangeType = MaximumRangeType,
|
QmlEventType(Message message = MaximumMessage, RangeType rangeType = MaximumRangeType,
|
||||||
int detailType = -1, const QmlEventLocation &location = QmlEventLocation(),
|
int detailType = -1, const QmlEventLocation &location = QmlEventLocation(),
|
||||||
const QString &data = QString(), const QString displayName = QString());
|
const QString &data = QString(), const QString displayName = QString());
|
||||||
|
@@ -148,8 +148,9 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
|
|||||||
{
|
{
|
||||||
const TraceEventLoader traceEventLoader = eventLoader ? [eventLoader](
|
const TraceEventLoader traceEventLoader = eventLoader ? [eventLoader](
|
||||||
const Timeline::TraceEvent &event, const Timeline::TraceEventType &type) {
|
const Timeline::TraceEvent &event, const Timeline::TraceEventType &type) {
|
||||||
return eventLoader(static_cast<const QmlEvent &>(event),
|
QTC_ASSERT(event.is<QmlEvent>(), return);
|
||||||
static_cast<const QmlEventType &>(type));
|
QTC_ASSERT(type.is<QmlEventType>(), return);
|
||||||
|
eventLoader(event.asConstRef<QmlEvent>(), type.asConstRef<QmlEventType>());
|
||||||
} : TraceEventLoader();
|
} : TraceEventLoader();
|
||||||
|
|
||||||
Timeline::TimelineTraceManager::registerFeatures(features, traceEventLoader, initializer,
|
Timeline::TimelineTraceManager::registerFeatures(features, traceEventLoader, initializer,
|
||||||
@@ -158,7 +159,10 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
|
|||||||
|
|
||||||
const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const
|
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,
|
void QmlProfilerModelManager::replayEvents(TraceEventLoader loader, Initializer initializer,
|
||||||
@@ -190,7 +194,8 @@ void QmlProfilerModelManager::replayQmlEvents(QmlEventLoader loader,
|
|||||||
if (future.isCanceled())
|
if (future.isCanceled())
|
||||||
return false;
|
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;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -462,13 +467,19 @@ void QmlProfilerEventTypeStorage::set(int typeId, Timeline::TraceEventType &&typ
|
|||||||
const size_t index = static_cast<size_t>(typeId);
|
const size_t index = static_cast<size_t>(typeId);
|
||||||
if (m_types.size() <= index)
|
if (m_types.size() <= index)
|
||||||
m_types.resize(index + 1);
|
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)
|
int QmlProfilerEventTypeStorage::append(Timeline::TraceEventType &&type)
|
||||||
{
|
{
|
||||||
const size_t index = m_types.size();
|
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());
|
QTC_ASSERT(index <= std::numeric_limits<int>::max(), return std::numeric_limits<int>::max());
|
||||||
return static_cast<int>(index);
|
return static_cast<int>(index);
|
||||||
}
|
}
|
||||||
@@ -495,7 +506,8 @@ QmlProfilerEventStorage::QmlProfilerEventStorage(
|
|||||||
|
|
||||||
int QmlProfilerEventStorage::append(Timeline::TraceEvent &&event)
|
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++;
|
return m_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user