diff options
Diffstat (limited to 'src/core/services/qsysteminformationservice.cpp')
-rw-r--r-- | src/core/services/qsysteminformationservice.cpp | 360 |
1 files changed, 354 insertions, 6 deletions
diff --git a/src/core/services/qsysteminformationservice.cpp b/src/core/services/qsysteminformationservice.cpp index f11e0c3d1..87cc08e59 100644 --- a/src/core/services/qsysteminformationservice.cpp +++ b/src/core/services/qsysteminformationservice.cpp @@ -40,10 +40,236 @@ #include "qsysteminformationservice_p.h" #include "qsysteminformationservice_p_p.h" +#ifdef Q_OS_ANDROID +#include <QtCore/QStandardPaths> +#endif + +#include <QtCore/QThreadPool> +#include <QtCore/QCoreApplication> +#include <QtCore/QFile> +#include <QtCore/QDateTime> +#include <QtCore/QUrl> +#include <QtCore/QDir> +#include <QtGui/QDesktopServices> + +#include <Qt3DCore/QAspectEngine> +#include <Qt3DCore/QAbstractAspect> +#include <Qt3DCore/private/qabstractaspect_p.h> +#include <Qt3DCore/private/qaspectengine_p.h> +#include <Qt3DCore/private/aspectcommanddebugger_p.h> + QT_BEGIN_NAMESPACE +namespace { + +struct FrameHeader +{ + FrameHeader() + : frameId(0) + , jobCount(0) + , frameType(WorkerJob) + { + } + + enum FrameType { + WorkerJob = 0, + Submission + }; + + quint32 frameId; + quint16 jobCount; + quint16 frameType; // Submission or worker job +}; + +} namespace Qt3DCore { +QSystemInformationServicePrivate::QSystemInformationServicePrivate(QAspectEngine *aspectEngine, + const QString &description) + : QAbstractServiceProviderPrivate(QServiceLocator::SystemInformation, description) + , m_aspectEngine(aspectEngine) + , m_submissionStorage(nullptr) + , m_frameId(0) + , m_commandDebugger(nullptr) +{ + m_traceEnabled = qEnvironmentVariableIsSet("QT3D_TRACE_ENABLED"); + m_graphicsTraceEnabled = qEnvironmentVariableIsSet("QT3D_GRAPHICS_TRACE_ENABLED"); + if (m_traceEnabled || m_graphicsTraceEnabled) + m_jobsStatTimer.start(); + + const bool commandServerEnabled = qEnvironmentVariableIsSet("QT3D_COMMAND_SERVER_ENABLED"); + if (commandServerEnabled) { + m_commandDebugger = new Debug::AspectCommandDebugger(q_func()); + m_commandDebugger->initialize(); + } +} + +QSystemInformationServicePrivate::~QSystemInformationServicePrivate() = default; + +QSystemInformationServicePrivate *QSystemInformationServicePrivate::get(QSystemInformationService *q) +{ + return q->d_func(); +} + +// Called by the jobs +void QSystemInformationServicePrivate::addJobLogStatsEntry(QSystemInformationServicePrivate::JobRunStats &stats) +{ + if (!m_traceEnabled && !m_graphicsTraceEnabled) + return; + + if (!m_jobStatsCached.hasLocalData()) { + auto jobVector = new QVector<JobRunStats>; + m_jobStatsCached.setLocalData(jobVector); + QMutexLocker lock(&m_localStoragesMutex); + m_localStorages.push_back(jobVector); + } + m_jobStatsCached.localData()->push_back(stats); +} + +// Called from Submission thread (which can be main thread in Manual drive mode) +void QSystemInformationServicePrivate::addSubmissionLogStatsEntry(QSystemInformationServicePrivate::JobRunStats &stats) +{ + if (!m_traceEnabled && !m_graphicsTraceEnabled) + return; + + QMutexLocker lock(&m_localStoragesMutex); + if (!m_jobStatsCached.hasLocalData()) { + m_submissionStorage = new QVector<JobRunStats>; + m_jobStatsCached.setLocalData(m_submissionStorage); + } + + // Handle the case where submission thread is also the main thread (Scene/Manual drive modes with no RenderThread) + if (m_submissionStorage == nullptr && m_jobStatsCached.hasLocalData()) + m_submissionStorage = new QVector<JobRunStats>; + + // When having no submission thread this can be null + m_submissionStorage->push_back(stats); +} + +// Called after jobs have been executed (MainThread QAspectJobManager::enqueueJobs) +void QSystemInformationServicePrivate::writeFrameJobLogStats() +{ + if (!m_traceEnabled && !m_graphicsTraceEnabled) + return; + + using JobRunStats = QSystemInformationServicePrivate::JobRunStats; + + if (!m_traceFile) { + const QString fileName = QStringLiteral("trace_") + QCoreApplication::applicationName() + + QDateTime::currentDateTime().toString(QStringLiteral("_yyMMdd-hhmmss_")) + + QSysInfo::productType() + QStringLiteral("_") + QSysInfo::buildAbi() + QStringLiteral(".qt3d"); +#ifdef Q_OS_ANDROID + m_traceFile.reset(new QFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QStringLiteral("/") + fileName)); +#else + // TODO fix for iOS + m_traceFile.reset(new QFile(fileName)); +#endif + if (!m_traceFile->open(QFile::WriteOnly|QFile::Truncate)) + qCritical("Failed to open trace file"); + } + + // Write Aspect + Job threads + { + FrameHeader header; + header.frameId = m_frameId; + header.jobCount = 0; + + for (const QVector<JobRunStats> *storage : qAsConst(m_localStorages)) + header.jobCount += storage->size(); + + m_traceFile->write(reinterpret_cast<char *>(&header), sizeof(FrameHeader)); + + for (QVector<JobRunStats> *storage : qAsConst(m_localStorages)) { + for (const JobRunStats &stat : *storage) + m_traceFile->write(reinterpret_cast<const char *>(&stat), sizeof(JobRunStats)); + storage->clear(); + } + } + + // Write submission thread + { + QMutexLocker lock(&m_localStoragesMutex); + const int submissionJobSize = m_submissionStorage != nullptr ? m_submissionStorage->size() : 0; + if (submissionJobSize > 0) { + FrameHeader header; + header.frameId = m_frameId; + header.jobCount = submissionJobSize; + header.frameType = FrameHeader::Submission; + + m_traceFile->write(reinterpret_cast<char *>(&header), sizeof(FrameHeader)); + + for (const JobRunStats &stat : *m_submissionStorage) + m_traceFile->write(reinterpret_cast<const char *>(&stat), sizeof(JobRunStats)); + m_submissionStorage->clear(); + } + } + + m_traceFile->flush(); + ++m_frameId; +} + +void QSystemInformationServicePrivate::updateTracing() +{ + if (m_traceEnabled || m_graphicsTraceEnabled) { + if (!m_jobsStatTimer.isValid()) + m_jobsStatTimer.start(); + } else { + m_traceFile.reset(); + } +} + + +QTaskLogger::QTaskLogger(QSystemInformationService *service, const JobId &jobId, Type type) + : m_service(service && service->isTraceEnabled() ? service : nullptr) + , m_type(type) +{ + m_stats.jobId = jobId; + if (m_service) { + m_stats.startTime = QSystemInformationServicePrivate::get(m_service)->m_jobsStatTimer.nsecsElapsed(); + m_stats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); + } +} + +QTaskLogger::QTaskLogger(QSystemInformationService *service, + const quint32 jobType, + const quint32 instance, + QTaskLogger::Type type) + : m_service(service && service->isTraceEnabled() ? service : nullptr) + , m_type(type) +{ + m_stats.jobId.typeAndInstance[0] = jobType; + m_stats.jobId.typeAndInstance[1] = instance; + if (m_service) { + m_stats.startTime = QSystemInformationServicePrivate::get(m_service)->m_jobsStatTimer.nsecsElapsed(); + m_stats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); + } +} + +QTaskLogger::~QTaskLogger() { + if (m_service) { + auto dservice = QSystemInformationServicePrivate::get(m_service); + if (m_stats.endTime == 0L) + m_stats.endTime = dservice->m_jobsStatTimer.nsecsElapsed(); + switch (m_type) { + case AspectJob: dservice->addJobLogStatsEntry(m_stats); break; + case Submission: dservice->addSubmissionLogStatsEntry(m_stats); break; + } + } +} + +void QTaskLogger::end(qint64 t) +{ + m_stats.endTime = t > 0 || !m_service ? t : QSystemInformationServicePrivate::get(m_service)->m_jobsStatTimer.nsecsElapsed(); +} + +qint64 QTaskLogger::restart() +{ + if (m_service) + m_stats.startTime = QSystemInformationServicePrivate::get(m_service)->m_jobsStatTimer.nsecsElapsed(); + return m_stats.startTime; +} + + /* !\internal \class Qt3DCore::QSystemInformationService \inmodule Qt3DCore @@ -58,8 +284,14 @@ namespace Qt3DCore { the new service. This constructor is protected so only subclasses can instantiate a QSystemInformationService object. */ -QSystemInformationService::QSystemInformationService(const QString &description) - : QAbstractServiceProvider(*new QSystemInformationServicePrivate(description)) + +QSystemInformationService::QSystemInformationService(QAspectEngine *aspectEngine) + : QAbstractServiceProvider(*new QSystemInformationServicePrivate(aspectEngine, QLatin1String("Default System Information Service"))) +{ +} + +QSystemInformationService::QSystemInformationService(QAspectEngine *aspectEngine, const QString &description) + : QAbstractServiceProvider(*new QSystemInformationServicePrivate(aspectEngine, description)) { } @@ -71,19 +303,135 @@ QSystemInformationService::QSystemInformationService(QSystemInformationServicePr { } +bool QSystemInformationService::isTraceEnabled() const +{ + Q_D(const QSystemInformationService); + return d->m_traceEnabled; +} + +bool QSystemInformationService::isGraphicsTraceEnabled() const +{ + Q_D(const QSystemInformationService); + return d->m_graphicsTraceEnabled; +} + +bool QSystemInformationService::isCommandServerEnabled() const +{ + Q_D(const QSystemInformationService); + return d->m_commandDebugger != nullptr; +} + +void QSystemInformationService::setTraceEnabled(bool traceEnabled) +{ + Q_D(QSystemInformationService); + if (d->m_traceEnabled != traceEnabled) { + d->m_traceEnabled = traceEnabled; + emit traceEnabledChanged(d->m_traceEnabled); + d->updateTracing(); + } +} + +void QSystemInformationService::setGraphicsTraceEnabled(bool graphicsTraceEnabled) +{ + Q_D(QSystemInformationService); + if (d->m_graphicsTraceEnabled != graphicsTraceEnabled) { + d->m_graphicsTraceEnabled = graphicsTraceEnabled; + emit graphicsTraceEnabledChanged(d->m_graphicsTraceEnabled); + d->updateTracing(); + } +} + /* \fn QStringList Qt3DCore::QSystemInformationService::aspectNames() const - Subclasses should override this function and return a string list containing the - names of all registered aspects. + Returns a string list containing the names of all registered aspects. */ +QStringList QSystemInformationService::aspectNames() const +{ + Q_D(const QSystemInformationService); + if (!d->m_aspectEngine) + return {}; + + QStringList res; + const auto aspects = d->m_aspectEngine->aspects(); + if (aspects.isEmpty()) + return { QLatin1String("No loaded aspects") }; + + QAspectEnginePrivate *dengine = QAspectEnginePrivate::get(d->m_aspectEngine); + for (auto aspect: aspects) { + const QString name = dengine->m_factory.aspectName(aspect); + if (!name.isEmpty()) + res << name; + else + res << QLatin1String("<unnamed>"); + } + + return res; +} /* \fn int Qt3DCore::QSystemInformationService::threadPoolThreadCount() const - Subclasses should override this function and return the number of threads in the - Qt3D task manager's threadpool. + Returns the maximum number of threads in the Qt3D task manager's threadpool. */ +int QSystemInformationService::threadPoolThreadCount() const +{ + return QThreadPool::globalInstance()->maxThreadCount(); +} + +void QSystemInformationService::writePreviousFrameTraces() +{ + Q_D(QSystemInformationService); + d->writeFrameJobLogStats(); +} + +void QSystemInformationService::revealLogFolder() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile(QDir::currentPath())); +} + +QVariant QSystemInformationService::executeCommand(const QString &command) +{ + Q_D(QSystemInformationService); + + if (command == QLatin1String("tracing on")) { + setTraceEnabled(true); + return {isTraceEnabled()}; + } + + if (command == QLatin1String("tracing off")) { + setTraceEnabled(false); + return {isTraceEnabled()}; + } + + if (command == QLatin1String("glprofiling on")) { + setGraphicsTraceEnabled(true); + return {isTraceEnabled()}; + } + + if (command == QLatin1String("glprofiling off")) { + setGraphicsTraceEnabled(false); + return {isTraceEnabled()}; + } + + return d->m_aspectEngine->executeCommand(command); +} + +void QSystemInformationService::dumpCommand(const QString &command) +{ + QVariant res = executeCommand(command); + QObject *obj = res.value<QObject *>(); + if (obj) { + auto reply = qobject_cast<Qt3DCore::Debug::AsynchronousCommandReply*>(obj); + if (reply) { + connect(reply, &Debug::AsynchronousCommandReply::finished, this, [reply]() { + qWarning() << qPrintable( QLatin1String(reply->data()) ); + }); + return; + } + } + qWarning() << qPrintable(res.toString()); +} } |