2016-04-26 11:50:59 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2016 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
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
#include "qmlprofilereventtypes.h"
|
|
|
|
|
|
2018-05-03 09:50:11 +02:00
|
|
|
#include <tracing/traceevent.h>
|
2018-03-27 17:39:17 +02:00
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
#include <QString>
|
2016-04-28 15:57:12 +02:00
|
|
|
#include <QByteArray>
|
|
|
|
|
#include <QVarLengthArray>
|
2016-05-10 13:18:12 +02:00
|
|
|
#include <QMetaType>
|
2016-04-28 15:57:12 +02:00
|
|
|
|
|
|
|
|
#include <initializer_list>
|
|
|
|
|
#include <type_traits>
|
2016-04-26 11:50:59 +02:00
|
|
|
|
|
|
|
|
namespace QmlProfiler {
|
|
|
|
|
|
2018-03-27 17:39:17 +02:00
|
|
|
struct QmlEvent : public Timeline::TraceEvent {
|
|
|
|
|
QmlEvent() : m_dataType(Inline8Bit), m_dataLength(0) {}
|
2016-04-28 15:57:12 +02:00
|
|
|
|
|
|
|
|
template<typename Number>
|
2016-05-04 12:48:35 +02:00
|
|
|
QmlEvent(qint64 timestamp, int typeIndex, std::initializer_list<Number> list)
|
2018-03-27 17:39:17 +02:00
|
|
|
: TraceEvent(timestamp, typeIndex)
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
assignNumbers<std::initializer_list<Number>, Number>(list);
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
2016-05-04 12:48:35 +02:00
|
|
|
QmlEvent(qint64 timestamp, int typeIndex, const QString &data)
|
2018-03-27 17:39:17 +02:00
|
|
|
: TraceEvent(timestamp, typeIndex)
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
assignNumbers<QByteArray, qint8>(data.toUtf8());
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
template<typename Number>
|
2016-05-04 12:48:35 +02:00
|
|
|
QmlEvent(qint64 timestamp, int typeIndex, const QVector<Number> &data)
|
2018-03-27 17:39:17 +02:00
|
|
|
: TraceEvent(timestamp, typeIndex)
|
2016-04-28 15:57:12 +02:00
|
|
|
{
|
|
|
|
|
assignNumbers<QVector<Number>, Number>(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QmlEvent(const QmlEvent &other)
|
2018-03-27 17:39:17 +02:00
|
|
|
: TraceEvent(other), m_dataType(other.m_dataType), m_dataLength(other.m_dataLength)
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
|
|
|
|
assignData(other);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-06 16:54:22 +02:00
|
|
|
QmlEvent(QmlEvent &&other)
|
|
|
|
|
{
|
|
|
|
|
memcpy(this, &other, sizeof(QmlEvent));
|
|
|
|
|
other.m_dataType = Inline8Bit; // prevent dtor from deleting the pointer
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
QmlEvent &operator=(const QmlEvent &other)
|
|
|
|
|
{
|
|
|
|
|
if (this != &other) {
|
2016-04-28 15:57:12 +02:00
|
|
|
clearPointer();
|
2018-03-27 17:39:17 +02:00
|
|
|
TraceEvent::operator=(other);
|
2016-04-26 11:50:59 +02:00
|
|
|
m_dataType = other.m_dataType;
|
2016-04-28 15:57:12 +02:00
|
|
|
m_dataLength = other.m_dataLength;
|
2016-04-26 11:50:59 +02:00
|
|
|
assignData(other);
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-06 16:54:22 +02:00
|
|
|
QmlEvent &operator=(QmlEvent &&other)
|
|
|
|
|
{
|
|
|
|
|
if (this != &other) {
|
|
|
|
|
memcpy(this, &other, sizeof(QmlEvent));
|
|
|
|
|
other.m_dataType = Inline8Bit;
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
~QmlEvent()
|
|
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
clearPointer();
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
template<typename Number>
|
|
|
|
|
Number number(int i) const
|
|
|
|
|
{
|
|
|
|
|
// Trailing zeroes can be omitted, for example for SceneGraph events
|
|
|
|
|
if (i >= m_dataLength)
|
|
|
|
|
return 0;
|
|
|
|
|
switch (m_dataType) {
|
|
|
|
|
case Inline8Bit:
|
|
|
|
|
return m_data.internal8bit[i];
|
|
|
|
|
case Inline16Bit:
|
|
|
|
|
return m_data.internal16bit[i];
|
|
|
|
|
case Inline32Bit:
|
|
|
|
|
return m_data.internal32bit[i];
|
|
|
|
|
case Inline64Bit:
|
|
|
|
|
return m_data.internal64bit[i];
|
|
|
|
|
case External8Bit:
|
|
|
|
|
return static_cast<const qint8 *>(m_data.external)[i];
|
|
|
|
|
case External16Bit:
|
|
|
|
|
return static_cast<const qint16 *>(m_data.external)[i];
|
|
|
|
|
case External32Bit:
|
|
|
|
|
return static_cast<const qint32 *>(m_data.external)[i];
|
|
|
|
|
case External64Bit:
|
|
|
|
|
return static_cast<const qint64 *>(m_data.external)[i];
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Number>
|
|
|
|
|
void setNumber(int i, Number number)
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
QVarLengthArray<Number> nums = numbers<QVarLengthArray<Number>, Number>();
|
|
|
|
|
int prevSize = nums.size();
|
|
|
|
|
if (i >= prevSize) {
|
|
|
|
|
nums.resize(i + 1);
|
|
|
|
|
// Fill with zeroes. We don't want to accidentally prevent squeezing.
|
|
|
|
|
while (prevSize < i)
|
|
|
|
|
nums[prevSize++] = 0;
|
|
|
|
|
}
|
|
|
|
|
nums[i] = number;
|
|
|
|
|
setNumbers<QVarLengthArray<Number>, Number>(nums);
|
|
|
|
|
}
|
2016-04-26 11:50:59 +02:00
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
template<typename Container, typename Number>
|
|
|
|
|
void setNumbers(const Container &numbers)
|
|
|
|
|
{
|
|
|
|
|
clearPointer();
|
|
|
|
|
assignNumbers<Container, Number>(numbers);
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
template<typename Number>
|
|
|
|
|
void setNumbers(std::initializer_list<Number> numbers)
|
|
|
|
|
{
|
|
|
|
|
setNumbers<std::initializer_list<Number>, Number>(numbers);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-06 15:38:14 +02:00
|
|
|
template<typename Container, typename Number = qint64>
|
2016-04-28 15:57:12 +02:00
|
|
|
Container numbers() const
|
|
|
|
|
{
|
|
|
|
|
Container container;
|
|
|
|
|
for (int i = 0; i < m_dataLength; ++i)
|
|
|
|
|
container.append(number<Number>(i));
|
|
|
|
|
return container;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString string() const
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
|
|
|
|
switch (m_dataType) {
|
2016-04-28 15:57:12 +02:00
|
|
|
case External8Bit:
|
2016-06-06 15:34:32 +02:00
|
|
|
return QString::fromUtf8(static_cast<const char *>(m_data.external), m_dataLength);
|
2016-04-28 15:57:12 +02:00
|
|
|
case Inline8Bit:
|
2016-06-06 15:34:32 +02:00
|
|
|
return QString::fromUtf8(m_data.internalChar, m_dataLength);
|
2016-04-28 15:57:12 +02:00
|
|
|
default:
|
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
|
return QString();
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
void setString(const QString &data)
|
|
|
|
|
{
|
|
|
|
|
clearPointer();
|
|
|
|
|
assignNumbers<QByteArray, char>(data.toUtf8());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Message rangeStage() const
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
Q_ASSERT(m_dataType == Inline8Bit);
|
|
|
|
|
return static_cast<Message>(m_data.internal8bit[0]);
|
|
|
|
|
}
|
2016-04-26 11:50:59 +02:00
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
void setRangeStage(Message stage)
|
|
|
|
|
{
|
|
|
|
|
clearPointer();
|
|
|
|
|
m_dataType = Inline8Bit;
|
|
|
|
|
m_dataLength = 1;
|
|
|
|
|
m_data.internal8bit[0] = stage;
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2016-04-28 15:57:12 +02:00
|
|
|
enum Type: quint16 {
|
|
|
|
|
External = 1,
|
|
|
|
|
Inline8Bit = 8,
|
|
|
|
|
External8Bit = Inline8Bit | External,
|
|
|
|
|
Inline16Bit = 16,
|
|
|
|
|
External16Bit = Inline16Bit | External,
|
|
|
|
|
Inline32Bit = 32,
|
|
|
|
|
External32Bit = Inline32Bit | External,
|
|
|
|
|
Inline64Bit = 64,
|
|
|
|
|
External64Bit = Inline64Bit | External
|
|
|
|
|
};
|
2016-04-26 11:50:59 +02:00
|
|
|
|
2018-03-27 17:39:17 +02:00
|
|
|
Type m_dataType;
|
|
|
|
|
quint16 m_dataLength;
|
2016-04-26 11:50:59 +02:00
|
|
|
|
2016-05-09 12:58:11 +02:00
|
|
|
static const int s_internalDataLength = 8;
|
2016-04-26 11:50:59 +02:00
|
|
|
union {
|
2016-04-28 15:57:12 +02:00
|
|
|
void *external;
|
2016-05-09 12:58:11 +02:00
|
|
|
char internalChar [s_internalDataLength];
|
|
|
|
|
qint8 internal8bit [s_internalDataLength];
|
|
|
|
|
qint16 internal16bit[s_internalDataLength / 2];
|
|
|
|
|
qint32 internal32bit[s_internalDataLength / 4];
|
|
|
|
|
qint64 internal64bit[s_internalDataLength / 8];
|
2016-04-28 15:57:12 +02:00
|
|
|
} m_data;
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
void assignData(const QmlEvent &other)
|
|
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
if (m_dataType & External) {
|
2018-03-27 17:37:24 +02:00
|
|
|
size_t length = m_dataLength * (other.m_dataType / 8);
|
2016-04-28 15:57:12 +02:00
|
|
|
m_data.external = malloc(length);
|
|
|
|
|
memcpy(m_data.external, other.m_data.external, length);
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(&m_data, &other.m_data, sizeof(m_data));
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 15:57:12 +02:00
|
|
|
template<typename Big, typename Small>
|
|
|
|
|
bool squeezable(Big source)
|
2016-04-26 11:50:59 +02:00
|
|
|
{
|
2016-04-28 15:57:12 +02:00
|
|
|
return static_cast<Small>(source) == source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Container, typename Number>
|
|
|
|
|
typename std::enable_if<(sizeof(Number) > 1), bool>::type
|
|
|
|
|
squeeze(const Container &numbers)
|
|
|
|
|
{
|
|
|
|
|
typedef typename QIntegerForSize<sizeof(Number) / 2>::Signed Small;
|
|
|
|
|
foreach (Number item, numbers) {
|
|
|
|
|
if (!squeezable<Number, Small>(item))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
assignNumbers<Container, Small>(numbers);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Container, typename Number>
|
|
|
|
|
typename std::enable_if<(sizeof(Number) <= 1), bool>::type
|
|
|
|
|
squeeze(const Container &)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename Container, typename Number>
|
|
|
|
|
void assignNumbers(const Container &numbers)
|
|
|
|
|
{
|
|
|
|
|
Number *data;
|
2018-03-27 17:37:24 +02:00
|
|
|
const auto size = numbers.size();
|
|
|
|
|
m_dataLength = squeezable<decltype(size), quint16>(size) ?
|
|
|
|
|
static_cast<quint16>(size) : std::numeric_limits<quint16>::max();
|
2016-04-28 15:57:12 +02:00
|
|
|
if (m_dataLength > sizeof(m_data) / sizeof(Number)) {
|
|
|
|
|
if (squeeze<Container, Number>(numbers))
|
|
|
|
|
return;
|
|
|
|
|
m_dataType = static_cast<Type>((sizeof(Number) * 8) | External);
|
|
|
|
|
m_data.external = malloc(m_dataLength * sizeof(Number));
|
|
|
|
|
data = static_cast<Number *>(m_data.external);
|
2016-04-26 11:50:59 +02:00
|
|
|
} else {
|
2016-04-28 15:57:12 +02:00
|
|
|
m_dataType = static_cast<Type>(sizeof(Number) * 8);
|
|
|
|
|
data = static_cast<Number *>(m_dataType & External ? m_data.external : &m_data);
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
2017-09-08 12:55:34 +02:00
|
|
|
quint16 i = 0;
|
|
|
|
|
for (Number item : numbers) {
|
|
|
|
|
if (i >= m_dataLength)
|
|
|
|
|
break;
|
2016-04-28 15:57:12 +02:00
|
|
|
data[i++] = item;
|
2017-09-08 12:55:34 +02:00
|
|
|
}
|
2016-04-28 15:57:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clearPointer()
|
|
|
|
|
{
|
|
|
|
|
if (m_dataType & External)
|
|
|
|
|
free(m_data.external);
|
2016-04-26 11:50:59 +02:00
|
|
|
}
|
2016-05-04 15:41:29 +02:00
|
|
|
|
|
|
|
|
friend QDataStream &operator>>(QDataStream &stream, QmlEvent &event);
|
|
|
|
|
friend QDataStream &operator<<(QDataStream &stream, const QmlEvent &event);
|
2016-04-26 11:50:59 +02:00
|
|
|
};
|
|
|
|
|
|
2016-05-04 15:41:29 +02:00
|
|
|
QDataStream &operator>>(QDataStream &stream, QmlEvent &event);
|
|
|
|
|
QDataStream &operator<<(QDataStream &stream, const QmlEvent &event);
|
|
|
|
|
|
2016-04-26 11:50:59 +02:00
|
|
|
} // namespace QmlProfiler
|
2016-05-04 18:51:08 +02:00
|
|
|
|
2016-05-10 13:18:12 +02:00
|
|
|
Q_DECLARE_METATYPE(QmlProfiler::QmlEvent)
|
|
|
|
|
|
2016-05-04 18:51:08 +02:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
Q_DECLARE_TYPEINFO(QmlProfiler::QmlEvent, Q_MOVABLE_TYPE);
|
|
|
|
|
QT_END_NAMESPACE
|