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
|
||||
|
||||
#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
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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 \
|
||||
|
@@ -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",
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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());
|
||||
|
@@ -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++;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user