diff options
Diffstat (limited to 'src/corelib/tracing')
-rw-r--r-- | src/corelib/tracing/qctf.cpp | 144 | ||||
-rw-r--r-- | src/corelib/tracing/qctf_p.h | 238 |
2 files changed, 382 insertions, 0 deletions
diff --git a/src/corelib/tracing/qctf.cpp b/src/corelib/tracing/qctf.cpp new file mode 100644 index 0000000000..ff81d0a678 --- /dev/null +++ b/src/corelib/tracing/qctf.cpp @@ -0,0 +1,144 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#define BUILD_LIBRARY + +#include <qthread.h> +#include <qpluginloader.h> +#include <qfileinfo.h> +#include <qdir.h> +#include <qjsonarray.h> + +#include "qctf_p.h" + +QT_BEGIN_NAMESPACE + +static bool s_initialized = false; +static bool s_triedLoading = false; +static bool s_prevent_recursion = false; +static bool s_shutdown = false; +static QCtfLib* s_plugin = nullptr; + +#if QT_CONFIG(library) && defined(QT_SHARED) + +#if defined(Q_OS_ANDROID) +static QString findPlugin(const QString &plugin) +{ + QString pluginPath = QString::fromUtf8(qgetenv("QT_PLUGIN_PATH")); + QDir dir(pluginPath); + const QStringList files = dir.entryList(QDir::Files); + for (const QString &file : files) { + if (file.contains(plugin)) + return QFileInfo(pluginPath + QLatin1Char('/') + file).absoluteFilePath(); + } + return {}; +} +#endif + +static bool loadPlugin(bool &retry) +{ + retry = false; +#ifdef Q_OS_WIN +#ifdef QT_DEBUG + QPluginLoader loader(QStringLiteral("tracing/QCtfTracePlugind.dll")); +#else + QPluginLoader loader(QStringLiteral("tracing/QCtfTracePlugin.dll")); +#endif +#elif defined(Q_OS_ANDROID) + + QString plugin = findPlugin(QStringLiteral("QCtfTracePlugin")); + if (plugin.isEmpty()) { + retry = true; + return false; + } + QPluginLoader loader(plugin); +#else + QPluginLoader loader(QStringLiteral("tracing/libQCtfTracePlugin.so")); +#endif + + if (!loader.isLoaded()) { + if (!loader.load()) + return false; + } + s_plugin = qobject_cast<QCtfLib *>(loader.instance()); + if (!s_plugin) + return false; + s_plugin->shutdown(&s_shutdown); + return true; +} + +#else + +#define QCtfPluginIID QStringLiteral("org.qt-project.Qt.QCtfLib") + +static bool loadPlugin(bool &retry) +{ + retry = false; + const auto &plugins = QPluginLoader::staticPlugins(); + for (const auto &plugin : plugins) { + const auto json = plugin.metaData(); + const auto IID = json[QStringLiteral("IID")]; + if (IID.toString() == QCtfPluginIID) { + s_plugin = qobject_cast<QCtfLib *>(plugin.instance()); + if (!s_plugin) + return false; + s_plugin->shutdown(&s_shutdown); + return true; + } + } + return false; +} + +#endif + +static bool initialize() +{ + if (s_shutdown || s_prevent_recursion) + return false; + if (s_initialized || s_triedLoading) + return s_initialized; + s_prevent_recursion = true; + bool retry = false; + if (!loadPlugin(retry)) { + if (!retry) { + s_triedLoading = true; + s_initialized = false; + } + } else { + bool enabled = s_plugin->sessionEnabled(); + if (!enabled) { + s_triedLoading = true; + s_initialized = false; + } else { + s_initialized = true; + } + } + s_prevent_recursion = false; + return s_initialized; +} + +bool _tracepoint_enabled(const QCtfTracePointEvent &point) +{ + if (!initialize()) + return false; + return s_plugin ? s_plugin->tracepointEnabled(point) : false; +} + +void _do_tracepoint(const QCtfTracePointEvent &point, const QByteArray &arr) +{ + if (!initialize()) + return; + if (s_plugin) + s_plugin->doTracepoint(point, arr); +} + +QCtfTracePointPrivate *_initialize_tracepoint(const QCtfTracePointEvent &point) +{ + if (!initialize()) + return nullptr; + return s_plugin ? s_plugin->initializeTracepoint(point) : nullptr; +} + +QT_END_NAMESPACE + +#include "moc_qctf_p.cpp" diff --git a/src/corelib/tracing/qctf_p.h b/src/corelib/tracing/qctf_p.h new file mode 100644 index 0000000000..70d00d018c --- /dev/null +++ b/src/corelib/tracing/qctf_p.h @@ -0,0 +1,238 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef Q_CTF_H +#define Q_CTF_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +// + +#include <qtcoreexports.h> +#include <qobject.h> + +QT_BEGIN_NAMESPACE + +struct QCtfTraceMetadata; +struct Q_CORE_EXPORT QCtfTracePointProvider +{ + const QString provider; + QCtfTraceMetadata *metadata; + QCtfTracePointProvider(const QString &provider) + : provider(provider), metadata(nullptr) + { + + } +}; + +struct Q_CORE_EXPORT QCtfTraceMetadata +{ + const QString name; + const QString metadata; + QCtfTraceMetadata(QCtfTracePointProvider &provider, const QString &name, const QString &metadata) + : name(name), metadata(metadata) + { + next = provider.metadata; + provider.metadata = this; + } + QCtfTraceMetadata *next = nullptr; +}; + +struct QCtfTracePointPrivate; +struct Q_CORE_EXPORT QCtfTracePointEvent +{ + const QCtfTracePointProvider &provider; + const QString eventName; + const QString metadata; + const int size; + const bool variableSize; + + QCtfTracePointEvent(const QCtfTracePointProvider &provider, const QString &name, const QString &metadata, int size, bool variableSize) + : provider(provider), eventName(name), metadata(metadata), size(size), variableSize(variableSize) + { + } + QCtfTracePointPrivate *d = nullptr; +}; + + + +Q_CORE_EXPORT bool _tracepoint_enabled(const QCtfTracePointEvent &point); +Q_CORE_EXPORT void _do_tracepoint(const QCtfTracePointEvent &point, const QByteArray &arr); +Q_CORE_EXPORT QCtfTracePointPrivate *_initialize_tracepoint(const QCtfTracePointEvent &point); + +#ifndef BUILD_LIBRARY +#include <QtCore/qbytearray.h> +#include <QtCore/qstring.h> +#include <QtCore/qurl.h> +namespace trace { +inline void toByteArray(QByteArray &) +{ +} + +inline void toByteArray(QByteArray &arr, const QString &value) +{ + arr.append(value.toUtf8()); + arr.append((char)0); +} + +inline void toByteArray(QByteArray &arr, const QUrl &value) +{ + arr.append(value.toString().toUtf8()); + arr.append((char)0); +} + +inline void toByteArray(QByteArray &arr, const QByteArray &data) +{ + arr.append(data); +} + +template <typename T> +inline void toByteArray(QByteArray &arr, T value) +{ + arr.append((char *)&value, sizeof(value)); +} + +template <typename T, typename... Ts> +inline void toByteArray(QByteArray &arr, T value, Ts... args) +{ + toByteArray(arr, value); + toByteArray(arr, args...); +} + +inline QByteArray toByteArray() +{ + return {}; +} + +template <typename... Ts> +inline QByteArray toByteArray(Ts... args) +{ + QByteArray data; + toByteArray(data, args...); + return data; +} + +template <typename T> +inline QByteArray toByteArrayFromArray(const T *values, int arraySize) +{ + QByteArray data; + data.append((char *)values, arraySize * sizeof(T)); + return data; +} + +template <typename IntegerType, typename T> +inline QByteArray toByteArrayFromEnum(T value) +{ + IntegerType e = static_cast<IntegerType>(value); + QByteArray data; + data.append((char *)&e, sizeof(e)); + return data; +} + +inline QByteArray toByteArrayFromCString(const char *str) +{ + QByteArray data; + if (str && *str != 0) + data.append(str); + data.append((char)0); + return data; +} + +static inline void appendFlags(QByteArray &data, quint8 &count, quint32 value) +{ + count = 0; + quint8 d = 1; + while (value) { + if (value&1) { + data.append(d); + count++; + } + d++; + value >>= 1; + } +} + +template <typename T> +inline QByteArray toByteArrayFromFlags(QFlags<T> value) +{ + quint32 intValue = static_cast<quint32>(value.toInt()); + quint8 count; + QByteArray data; + data.append((char)0); + if (intValue == 0) { + data.append((char)0); + data.data()[0] = 1; + } else { + appendFlags(data, count, intValue); + data.data()[0] = count; + } + return data; +} + +} // trace + +#define _DEFINE_EVENT(provider, event, metadata, size, varSize) \ + static QCtfTracePointEvent _ctf_ ## event = QCtfTracePointEvent(_ctf_provider_ ## provider, QStringLiteral(QT_STRINGIFY(event)), metadata, size, varSize); +#define _DEFINE_METADATA(provider, name, metadata) \ + static QCtfTraceMetadata _ctf_metadata_ ## name = QCtfTraceMetadata(_ctf_provider_ ## provider, QStringLiteral(QT_STRINGIFY(name)), metadata); +#define _DEFINE_TRACEPOINT_PROVIDER(provider) \ + static QCtfTracePointProvider _ctf_provider_ ## provider = QCtfTracePointProvider(QStringLiteral(QT_STRINGIFY(provider))); + +#define TRACEPOINT_EVENT(provider, event, metadata, size, varSize) \ + _DEFINE_EVENT(provider, event, metadata, size, varSize) + +#define TRACEPOINT_PROVIDER(provider) \ + _DEFINE_TRACEPOINT_PROVIDER(provider) + +#define TRACEPOINT_METADATA(provider, name, metadata) \ + _DEFINE_METADATA(provider, name, metadata) + +#define tracepoint_enabled(provider, event) \ + _tracepoint_enabled(_ctf_ ## event) + +#define do_tracepoint(provider, event, ...) \ +{ \ + auto &tp = _ctf_ ## event; \ + if (!tp.d) \ + tp.d = _initialize_tracepoint(tp); \ + if (tp.d) { \ + QByteArray data(tp.size, 0); \ + if (!tp.metadata.isEmpty()) \ + data = trace::toByteArray(__VA_ARGS__); \ + _do_tracepoint(tp, data); \ + } \ +} + +#define tracepoint(provider, name, ...) \ + do { \ + if (tracepoint_enabled(provider, name)) \ + do_tracepoint(provider, name, __VA_ARGS__); \ + } while (0) + +#endif + +class Q_CORE_EXPORT QCtfLib : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QCtfLib) +public: + explicit QCtfLib(QObject *parent = nullptr) : QObject(parent) {} + virtual ~QCtfLib() = default; + virtual bool tracepointEnabled(const QCtfTracePointEvent &point) = 0; + virtual void doTracepoint(const QCtfTracePointEvent &point, const QByteArray &arr) = 0; + virtual bool sessionEnabled() = 0; + virtual QCtfTracePointPrivate *initializeTracepoint(const QCtfTracePointEvent &point) = 0; + virtual void shutdown(bool *shutdown) = 0; +}; + +QT_END_NAMESPACE + +#endif |