diff options
41 files changed, 442 insertions, 361 deletions
diff --git a/src/core/aspects/qaspectmanager.cpp b/src/core/aspects/qaspectmanager.cpp index f24248399..240955a06 100644 --- a/src/core/aspects/qaspectmanager.cpp +++ b/src/core/aspects/qaspectmanager.cpp @@ -57,6 +57,7 @@ #include <Qt3DCore/private/qchangearbiter_p.h> #include <Qt3DCore/private/qscheduler_p.h> #include <Qt3DCore/private/qservicelocator_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p_p.h> #include <Qt3DCore/private/qthreadpooler_p.h> #include <Qt3DCore/private/qtickclock_p.h> #include <Qt3DCore/private/qtickclockservice_p.h> @@ -449,57 +450,49 @@ void QAspectManager::processFrame() // // Doing this as the first call in the new frame ensures the lock free approach works // without any such data race. -#if QT_CONFIG(qt3d_profile_jobs) - const quint32 arbiterId = 4096; - JobRunStats changeArbiterStats; - changeArbiterStats.jobId.typeAndInstance[0] = arbiterId; - changeArbiterStats.jobId.typeAndInstance[1] = 0; - changeArbiterStats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); - changeArbiterStats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); -#endif - - // Tell the NodePostConstructorInit to process any pending nodes which will add them to our list of - // tree changes - m_postConstructorInit->processNodes(); - - // Add and Remove Nodes - const QVector<NodeTreeChange> nodeTreeChanges = std::move(m_nodeTreeChanges); - for (const NodeTreeChange &change : nodeTreeChanges) { - // Buckets ensure that even if we have intermingled node added / removed - // buckets, we preserve the order of the sequences - - for (QAbstractAspect *aspect : qAsConst(m_aspects)) { - switch (change.type) { - case NodeTreeChange::Added: - aspect->d_func()->createBackendNode(change); - break; - case NodeTreeChange::Removed: - aspect->d_func()->clearBackendNode(change); - break; + { + // scope for QTaskLogger + QTaskLogger logger(m_serviceLocator->systemInformation(), 4096, 0); + + // Tell the NodePostConstructorInit to process any pending nodes which will add them to our list of + // tree changes + m_postConstructorInit->processNodes(); + + // Add and Remove Nodes + const QVector<NodeTreeChange> nodeTreeChanges = std::move(m_nodeTreeChanges); + for (const NodeTreeChange &change : nodeTreeChanges) { + // Buckets ensure that even if we have intermingled node added / removed + // buckets, we preserve the order of the sequences + + for (QAbstractAspect *aspect : qAsConst(m_aspects)) { + switch (change.type) { + case NodeTreeChange::Added: + aspect->d_func()->createBackendNode(change); + break; + case NodeTreeChange::Removed: + aspect->d_func()->clearBackendNode(change); + break; + } } } - } - // Sync node / subnode relationship changes - const auto dirtySubNodes = m_changeArbiter->takeDirtyFrontEndSubNodes(); - if (dirtySubNodes.size()) - for (QAbstractAspect *aspect : qAsConst(m_aspects)) - QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndSubNodes(dirtySubNodes); - - // Sync property updates - const auto dirtyFrontEndNodes = m_changeArbiter->takeDirtyFrontEndNodes(); - if (dirtyFrontEndNodes.size()) - for (QAbstractAspect *aspect : qAsConst(m_aspects)) - QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndNodes(dirtyFrontEndNodes); - - // TO DO: Having this done in the main thread actually means aspects could just - // as simply read info out of the Frontend classes without risk of introducing - // races. This could therefore be removed for Qt 6. - m_changeArbiter->syncChanges(); -#if QT_CONFIG(qt3d_profile_jobs) - changeArbiterStats.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - QThreadPooler::addJobLogStatsEntry(changeArbiterStats); -#endif + // Sync node / subnode relationship changes + const auto dirtySubNodes = m_changeArbiter->takeDirtyFrontEndSubNodes(); + if (dirtySubNodes.size()) + for (QAbstractAspect *aspect : qAsConst(m_aspects)) + QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndSubNodes(dirtySubNodes); + + // Sync property updates + const auto dirtyFrontEndNodes = m_changeArbiter->takeDirtyFrontEndNodes(); + if (dirtyFrontEndNodes.size()) + for (QAbstractAspect *aspect : qAsConst(m_aspects)) + QAbstractAspectPrivate::get(aspect)->syncDirtyFrontEndNodes(dirtyFrontEndNodes); + + // TO DO: Having this done in the main thread actually means aspects could just + // as simply read info out of the Frontend classes without risk of introducing + // races. This could therefore be removed for Qt 6. + m_changeArbiter->syncChanges(); + } // For each Aspect // Ask them to launch set of jobs for the current frame @@ -512,8 +505,6 @@ void QAspectManager::processFrame() #if defined(QT3D_CORE_JOB_TIMING) qDebug() << "Jobs took" << timer.nsecsElapsed() / 1.0e6; #endif - - // TODO sync backend changes to frontend } } // namespace Qt3DCore diff --git a/src/core/jobs/qaspectjob_p.h b/src/core/jobs/qaspectjob_p.h index b16c3cad2..ddad09c86 100644 --- a/src/core/jobs/qaspectjob_p.h +++ b/src/core/jobs/qaspectjob_p.h @@ -54,6 +54,7 @@ #include <QtCore/QWeakPointer> #include <Qt3DCore/private/qt3dcore_global_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p_p.h> #include <Qt3DCore/qt3dcore-config.h> QT_BEGIN_NAMESPACE @@ -63,47 +64,6 @@ namespace Qt3DCore { class QAspectJob; class QAspectManager; -#if QT_CONFIG(qt3d_profile_jobs) -struct FrameHeader -{ - FrameHeader() - : frameId(0) - , jobCount(0) - , frameType(WorkerJob) - { - } - - enum FrameType { - WorkerJob = 0, - Submission - }; - - quint32 frameId; - quint16 jobCount; - quint16 frameType; // Submission or worker job -}; - -union JobId -{ - quint32 typeAndInstance[2]; - quint64 id; -}; - -struct JobRunStats -{ - JobRunStats() - { - jobId.id = 0; - } - - qint64 startTime; - qint64 endTime; - JobId jobId; - // QAspectJob subclasses should properly populate the jobId - quint64 threadId; -}; -#endif - class Q_3DCORE_PRIVATE_EXPORT QAspectJobPrivate { public: @@ -115,29 +75,16 @@ public: virtual void postFrame(QAspectManager *aspectManager); QVector<QWeakPointer<QAspectJob> > m_dependencies; -#if QT_CONFIG(qt3d_profile_jobs) - JobRunStats m_stats; -#endif + JobId m_jobId; }; - } // Qt3D -#if QT_CONFIG(qt3d_profile_jobs) - -#include <Qt3DCore/private/qaspectjob_p.h> - #define SET_JOB_RUN_STAT_TYPE(job, type, instance) \ - Qt3DCore::QAspectJobPrivate::get(job)->m_stats.jobId.typeAndInstance[0] = type; \ - Qt3DCore::QAspectJobPrivate::get(job)->m_stats.jobId.typeAndInstance[1] = instance; - -#else - -#define SET_JOB_RUN_STAT_TYPE(job, type, instance) \ - Q_UNUSED(job) \ - Q_UNUSED(type) \ - Q_UNUSED(instance) - -#endif + { \ + auto &jobId = Qt3DCore::QAspectJobPrivate::get(job)->m_jobId; \ + jobId.typeAndInstance[0] = type; \ + jobId.typeAndInstance[1] = instance; \ + } QT_END_NAMESPACE diff --git a/src/core/jobs/qaspectjobmanager.cpp b/src/core/jobs/qaspectjobmanager.cpp index 91394924f..be7942359 100644 --- a/src/core/jobs/qaspectjobmanager.cpp +++ b/src/core/jobs/qaspectjobmanager.cpp @@ -44,7 +44,7 @@ #include <QtCore/QDebug> #include <QtCore/QThread> #include <QtCore/QFuture> - +#include <Qt3DCore/private/qaspectmanager_p.h> #include <Qt3DCore/private/qthreadpooler_p.h> #include <Qt3DCore/private/task_p.h> @@ -52,9 +52,10 @@ QT_BEGIN_NAMESPACE namespace Qt3DCore { -QAspectJobManager::QAspectJobManager(QObject *parent) +QAspectJobManager::QAspectJobManager(QAspectManager *parent) : QAbstractAspectJobManager(parent) , m_threadPooler(new QThreadPooler(this)) + , m_aspectManager(parent) { } @@ -69,12 +70,16 @@ void QAspectJobManager::initialize() // Adds all Aspect Jobs to be processed for a frame void QAspectJobManager::enqueueJobs(const QVector<QAspectJobPtr> &jobQueue) { + auto systemService = m_aspectManager ? m_aspectManager->serviceLocator()->systemInformation() : nullptr; + if (systemService) + systemService->writePreviousFrameTraces(); + // Convert QJobs to Tasks QHash<QAspectJob *, AspectTaskRunnable *> tasksMap; QVector<RunnableInterface *> taskList; taskList.reserve(jobQueue.size()); for (const QAspectJobPtr &job : jobQueue) { - AspectTaskRunnable *task = new AspectTaskRunnable(); + AspectTaskRunnable *task = new AspectTaskRunnable(systemService); task->m_job = job; tasksMap.insert(job.data(), task); @@ -99,9 +104,6 @@ void QAspectJobManager::enqueueJobs(const QVector<QAspectJobPtr> &jobQueue) taskDepender->m_dependerCount += dependerCount; } -#if QT_CONFIG(qt3d_profile_jobs) - QThreadPooler::writeFrameJobLogStats(); -#endif m_threadPooler->mapDependables(taskList); } diff --git a/src/core/jobs/qaspectjobmanager_p.h b/src/core/jobs/qaspectjobmanager_p.h index 77e535491..acbd0263e 100644 --- a/src/core/jobs/qaspectjobmanager_p.h +++ b/src/core/jobs/qaspectjobmanager_p.h @@ -63,12 +63,13 @@ namespace Qt3DCore { class QThreadPooler; class DependencyHandler; +class QAspectManager; class Q_3DCORE_PRIVATE_EXPORT QAspectJobManager : public QAbstractAspectJobManager { Q_OBJECT public: - explicit QAspectJobManager(QObject *parent = 0); + explicit QAspectJobManager(QAspectManager *parent = nullptr); ~QAspectJobManager(); void initialize() override; @@ -81,6 +82,7 @@ public: private: QThreadPooler *m_threadPooler; + QAspectManager *m_aspectManager; }; } // namespace Qt3DCore diff --git a/src/core/jobs/qthreadpooler.cpp b/src/core/jobs/qthreadpooler.cpp index 3ab321542..f5c50062a 100644 --- a/src/core/jobs/qthreadpooler.cpp +++ b/src/core/jobs/qthreadpooler.cpp @@ -40,27 +40,10 @@ #include "qthreadpooler_p.h" #include <QtCore/QDebug> -#if QT_CONFIG(qt3d_profile_jobs) - -#ifdef Q_OS_ANDROID -#include <QtCore/QStandardPaths> -#endif - -#include <QtCore/QCoreApplication> -#include <QtCore/QFile> -#include <QtCore/QThreadStorage> -#include <QtCore/QDateTime> -#include <QtCore/QCoreApplication> -#endif - QT_BEGIN_NAMESPACE namespace Qt3DCore { -#if QT_CONFIG(qt3d_profile_jobs) -QElapsedTimer QThreadPooler::m_jobsStatTimer; -#endif - QThreadPooler::QThreadPooler(QObject *parent) : QObject(parent) , m_futureInterface(nullptr) @@ -76,12 +59,8 @@ QThreadPooler::QThreadPooler(QObject *parent) m_threadPool->setMaxThreadCount(maxThreadCountValue); } - // Ensures that threads will never be recycled m_threadPool->setExpiryTimeout(-1); -#if QT_CONFIG(qt3d_profile_jobs) - QThreadPooler::m_jobsStatTimer.start(); -#endif } QThreadPooler::~QThreadPooler() @@ -194,102 +173,6 @@ int QThreadPooler::maxThreadCount() const return m_threadPool->maxThreadCount(); } -#if QT_CONFIG(qt3d_profile_jobs) - -QThreadStorage<QVector<JobRunStats> *> jobStatsCached; - -QVector<QVector<JobRunStats> *> localStorages; -QVector<JobRunStats> *submissionStorage = nullptr; - -QMutex localStoragesMutex; - -// Called by the jobs -void QThreadPooler::addJobLogStatsEntry(JobRunStats &stats) -{ - if (!jobStatsCached.hasLocalData()) { - auto jobVector = new QVector<JobRunStats>; - jobStatsCached.setLocalData(jobVector); - QMutexLocker lock(&localStoragesMutex); - localStorages.push_back(jobVector); - } - jobStatsCached.localData()->push_back(stats); -} - -// Called after jobs have been executed (MainThread QAspectJobManager::enqueueJobs) -void QThreadPooler::writeFrameJobLogStats() -{ - static QScopedPointer<QFile> traceFile; - static quint32 frameId = 0; - if (!traceFile) { - const QString fileName = QStringLiteral("trace_") + QCoreApplication::applicationName() + QDateTime::currentDateTime().toString(QStringLiteral("_ddd_dd_MM_yy-hh_mm_ss_"))+ QSysInfo::productType() + QStringLiteral("_") + QSysInfo::buildAbi() + QStringLiteral(".qt3d"); -#ifdef Q_OS_ANDROID - traceFile.reset(new QFile(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + QStringLiteral("/") + fileName)); -#else - traceFile.reset(new QFile(fileName)); -#endif - if (!traceFile->open(QFile::WriteOnly|QFile::Truncate)) - qCritical("Failed to open trace file"); - } - - // Write Aspect + Job threads - { - FrameHeader header; - header.frameId = frameId; - header.jobCount = 0; - - for (const QVector<JobRunStats> *storage : qAsConst(localStorages)) - header.jobCount += storage->size(); - - traceFile->write(reinterpret_cast<char *>(&header), sizeof(FrameHeader)); - - for (QVector<JobRunStats> *storage : qAsConst(localStorages)) { - for (const JobRunStats &stat : *storage) - traceFile->write(reinterpret_cast<const char *>(&stat), sizeof(JobRunStats)); - storage->clear(); - } - } - - // Write submission thread - { - QMutexLocker lock(&localStoragesMutex); - const int submissionJobSize = submissionStorage != nullptr ? submissionStorage->size() : 0; - if (submissionJobSize > 0) { - FrameHeader header; - header.frameId = frameId; - header.jobCount = submissionJobSize; - header.frameType = FrameHeader::Submission; - - traceFile->write(reinterpret_cast<char *>(&header), sizeof(FrameHeader)); - - for (const JobRunStats &stat : *submissionStorage) - traceFile->write(reinterpret_cast<const char *>(&stat), sizeof(JobRunStats)); - submissionStorage->clear(); - } - } - - traceFile->flush(); - ++frameId; -} - -// Called from Submission thread (which can be main thread in Manual drive mode) -void QThreadPooler::addSubmissionLogStatsEntry(JobRunStats &stats) -{ - QMutexLocker lock(&localStoragesMutex); - if (!jobStatsCached.hasLocalData()) { - submissionStorage = new QVector<JobRunStats>; - jobStatsCached.setLocalData(submissionStorage); - } - - // Handle the case where submission thread is also the main thread (Scene/Manual drive modes with no RenderThread) - if (submissionStorage == nullptr && jobStatsCached.hasLocalData()) - submissionStorage = new QVector<JobRunStats>; - - // When having no submission thread this can be null - submissionStorage->push_back(stats); -} - -#endif - } // namespace Qt3DCore QT_END_NAMESPACE diff --git a/src/core/jobs/qthreadpooler_p.h b/src/core/jobs/qthreadpooler_p.h index 3e17cbd6d..1970641b8 100644 --- a/src/core/jobs/qthreadpooler_p.h +++ b/src/core/jobs/qthreadpooler_p.h @@ -60,10 +60,6 @@ #include <Qt3DCore/private/qaspectjob_p.h> #include <Qt3DCore/private/task_p.h> -#if QT_CONFIG(qt3d_profile_jobs) -#include <QtCore/QElapsedTimer> -#endif - QT_BEGIN_NAMESPACE namespace Qt3DCore { @@ -81,17 +77,6 @@ public: QFuture<void> future(); int maxThreadCount() const; -#if QT_CONFIG(qt3d_profile_jobs) - static QElapsedTimer m_jobsStatTimer; - - // Aspects + Job threads - static void addJobLogStatsEntry(JobRunStats &stats); - static void writeFrameJobLogStats(); - - // Submission thread - static void addSubmissionLogStatsEntry(JobRunStats &stats); - -#endif private: void enqueueTasks(const QVector<RunnableInterface *> &tasks); diff --git a/src/core/jobs/task.cpp b/src/core/jobs/task.cpp index 7c3ebf6eb..1dd5712c9 100644 --- a/src/core/jobs/task.cpp +++ b/src/core/jobs/task.cpp @@ -44,6 +44,7 @@ #include <QtCore/QMutexLocker> #include <Qt3DCore/private/qthreadpooler_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p_p.h> QT_BEGIN_NAMESPACE @@ -55,8 +56,9 @@ RunnableInterface::~RunnableInterface() // Aspect task -AspectTaskRunnable::AspectTaskRunnable() - : m_pooler(nullptr) +AspectTaskRunnable::AspectTaskRunnable(QSystemInformationService *service) + : m_service(service) + , m_pooler(nullptr) , m_id(0) , m_reserved(false) { @@ -69,21 +71,9 @@ AspectTaskRunnable::~AspectTaskRunnable() void AspectTaskRunnable::run() { if (m_job) { -#if QT_CONFIG(qt3d_profile_jobs) QAspectJobPrivate *jobD = QAspectJobPrivate::get(m_job.data()); - if (m_pooler) { - jobD->m_stats.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - jobD->m_stats.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); - } -#endif + QTaskLogger logger(m_pooler ? m_service : nullptr, jobD->m_jobId, QTaskLogger::AspectJob); m_job->run(); -#if QT_CONFIG(qt3d_profile_jobs) - if (m_pooler) { - jobD->m_stats.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - // Add current job's stats to log output - QThreadPooler::addJobLogStatsEntry(jobD->m_stats); - } -#endif } // We could have an append sub task or something in here diff --git a/src/core/jobs/task_p.h b/src/core/jobs/task_p.h index c81882719..ff411539f 100644 --- a/src/core/jobs/task_p.h +++ b/src/core/jobs/task_p.h @@ -65,6 +65,7 @@ namespace Qt3DCore { class JobRunner; class DependencyHandler; class QThreadPooler; +class QSystemInformationService; class RunnableInterface : public QRunnable { @@ -92,7 +93,7 @@ public: class AspectTaskRunnable : public RunnableInterface { public: - AspectTaskRunnable(); + AspectTaskRunnable(QSystemInformationService *service); ~AspectTaskRunnable(); void run() override; @@ -113,6 +114,7 @@ public: int m_dependerCount = 0; private: + QSystemInformationService *m_service; QThreadPooler *m_pooler; int m_id; // For testing purposes for now bool m_reserved; diff --git a/src/core/services/nullservices_p.h b/src/core/services/nullservices_p.h index 30dc2d543..6b2d1b029 100644 --- a/src/core/services/nullservices_p.h +++ b/src/core/services/nullservices_p.h @@ -54,25 +54,11 @@ #include <Qt3DCore/qt3dcore_global.h> #include <Qt3DCore/private/qopenglinformationservice_p.h> -#include <Qt3DCore/private/qsysteminformationservice_p.h> QT_BEGIN_NAMESPACE namespace Qt3DCore { -class NullSystemInformationService : public QSystemInformationService -{ -public: - NullSystemInformationService() - : QSystemInformationService(QStringLiteral("Null System Information Service")) - {} - ~NullSystemInformationService() {} - - QStringList aspectNames() const final { return QStringList(); } - int threadPoolThreadCount() const final { return 0; } -}; - - class NullOpenGLInformationService : public QOpenGLInformationService { public: diff --git a/src/core/services/qservicelocator.cpp b/src/core/services/qservicelocator.cpp index bdcb4a521..5df33dae9 100644 --- a/src/core/services/qservicelocator.cpp +++ b/src/core/services/qservicelocator.cpp @@ -46,6 +46,7 @@ #include <Qt3DCore/private/qdownloadhelperservice_p.h> #include <Qt3DCore/private/qeventfilterservice_p.h> #include <Qt3DCore/private/qtickclockservice_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p.h> QT_BEGIN_NAMESPACE @@ -94,7 +95,7 @@ public: QHash<int, QAbstractServiceProvider *> m_services; - NullSystemInformationService m_nullSystemInfo; + QSystemInformationService m_systemInfo; NullOpenGLInformationService m_nullOpenGLInfo; QTickClockService m_defaultFrameAdvanceService; QEventFilterService m_eventFilterService; @@ -196,7 +197,7 @@ int QServiceLocator::serviceCount() const QSystemInformationService *QServiceLocator::systemInformation() { Q_D(QServiceLocator); - return static_cast<QSystemInformationService *>(d->m_services.value(SystemInformation, &d->m_nullSystemInfo)); + return static_cast<QSystemInformationService *>(d->m_services.value(SystemInformation, &d->m_systemInfo)); } /* diff --git a/src/core/services/qsysteminformationservice.cpp b/src/core/services/qsysteminformationservice.cpp index f11e0c3d1..6a8cbee04 100644 --- a/src/core/services/qsysteminformationservice.cpp +++ b/src/core/services/qsysteminformationservice.cpp @@ -40,10 +40,206 @@ #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/QCoreApplication> + 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(const QString &description) + : QAbstractServiceProviderPrivate(QServiceLocator::SystemInformation, description) + , m_submissionStorage(nullptr) + , m_frameId(0) +{ + m_traceEnabled = qEnvironmentVariableIsSet("QT3D_TRACE_ENABLED"); + if (m_traceEnabled) + m_jobsStatTimer.start(); +} + +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) + 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) + 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) + return; + + using JobRunStats = QSystemInformationServicePrivate::JobRunStats; + + if (!m_traceFile) { + const QString fileName = QStringLiteral("trace_") + QCoreApplication::applicationName() + QDateTime::currentDateTime().toString(QStringLiteral("_ddd_dd_MM_yy-hh_mm_ss_"))+ 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; +} + + +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,6 +254,12 @@ namespace Qt3DCore { the new service. This constructor is protected so only subclasses can instantiate a QSystemInformationService object. */ + +QSystemInformationService::QSystemInformationService() + : QAbstractServiceProvider(*new QSystemInformationServicePrivate(QLatin1String("Default System Information Service"))) +{ +} + QSystemInformationService::QSystemInformationService(const QString &description) : QAbstractServiceProvider(*new QSystemInformationServicePrivate(description)) { @@ -71,19 +273,52 @@ QSystemInformationService::QSystemInformationService(QSystemInformationServicePr { } +bool QSystemInformationService::isTraceEnabled() const +{ + Q_D(const QSystemInformationService); + return d->m_traceEnabled; +} + +void QSystemInformationService::setTraceEnabled(bool traceEnabled) +{ + Q_D(QSystemInformationService); + if (d->m_traceEnabled != traceEnabled) { + d->m_traceEnabled = traceEnabled; + emit traceEnabledChanged(d->m_traceEnabled); + if (d->m_traceEnabled) { + if (!d->m_jobsStatTimer.isValid()) + d->m_jobsStatTimer.start(); + } else { + d->m_traceFile.reset(); + } + } +} + /* \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 +{ + return {}; +} /* \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(); +} } diff --git a/src/core/services/qsysteminformationservice_p.h b/src/core/services/qsysteminformationservice_p.h index a8a83701b..6fc1579bc 100644 --- a/src/core/services/qsysteminformationservice_p.h +++ b/src/core/services/qsysteminformationservice_p.h @@ -61,16 +61,29 @@ QT_BEGIN_NAMESPACE namespace Qt3DCore { class QSystemInformationServicePrivate; +struct JobRunStats; class Q_3DCORESHARED_EXPORT QSystemInformationService : public QAbstractServiceProvider { Q_OBJECT + Q_PROPERTY(bool traceEnabled READ isTraceEnabled WRITE setTraceEnabled NOTIFY traceEnabledChanged) public: - virtual QStringList aspectNames() const = 0; - virtual int threadPoolThreadCount() const = 0; + QSystemInformationService(); + + bool isTraceEnabled() const; + void setTraceEnabled(bool traceEnabled); + + QStringList aspectNames() const; + int threadPoolThreadCount() const; + + void writePreviousFrameTraces(); + +signals: + void traceEnabledChanged(bool traceEnabled); protected: - QSystemInformationService(const QString &description = QString()); + Q_DECLARE_PRIVATE(QSystemInformationService) + QSystemInformationService(const QString &description); QSystemInformationService(QSystemInformationServicePrivate &dd); }; diff --git a/src/core/services/qsysteminformationservice_p_p.h b/src/core/services/qsysteminformationservice_p_p.h index e3ce9fe49..75a6e98e7 100644 --- a/src/core/services/qsysteminformationservice_p_p.h +++ b/src/core/services/qsysteminformationservice_p_p.h @@ -51,21 +51,91 @@ // We mean it. // -#include <Qt3DCore/qt3dcore_global.h> +#include <QtCore/QThreadStorage> +#include <QtCore/QElapsedTimer> +#include <QtCore/QFile> +#include <QtCore/QMutex> +#include <Qt3DCore/qt3dcore_global.h> +#include <Qt3DCore/private/qt3dcore_global_p.h> #include <Qt3DCore/private/qabstractserviceprovider_p.h> #include <Qt3DCore/private/qservicelocator_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p.h> QT_BEGIN_NAMESPACE namespace Qt3DCore { -class QSystemInformationServicePrivate : public QAbstractServiceProviderPrivate +union Q_3DCORE_PRIVATE_EXPORT JobId +{ + JobId() : id(0L) { } + JobId(quint32 t, quint32 i) { typeAndInstance[0] = t; typeAndInstance[1] = i; } + + quint32 typeAndInstance[2]; + quint64 id; +}; + +class Q_3DCORE_PRIVATE_EXPORT QSystemInformationServicePrivate : public QAbstractServiceProviderPrivate { public: - QSystemInformationServicePrivate(const QString &description) - : QAbstractServiceProviderPrivate(QServiceLocator::SystemInformation, description) - {} + struct JobRunStats + { + JobRunStats() { jobId.id = 0; startTime = 0L; endTime = 0L; } + + qint64 startTime; + qint64 endTime; + JobId jobId; // QAspectJob subclasses should properly populate the jobId + quint64 threadId; + }; + + QSystemInformationServicePrivate(const QString &description); + ~QSystemInformationServicePrivate(); + + static QSystemInformationServicePrivate *get(QSystemInformationService *q); + + // Aspects + Job threads + void addJobLogStatsEntry(JobRunStats &stats); + + // Submission thread + void addSubmissionLogStatsEntry(JobRunStats &stats); + + void writeFrameJobLogStats(); + + bool m_traceEnabled; + + QElapsedTimer m_jobsStatTimer; + QThreadStorage<QVector<JobRunStats> *> m_jobStatsCached; + + QVector<QVector<JobRunStats> *> m_localStorages; + QVector<JobRunStats> *m_submissionStorage; + + QMutex m_localStoragesMutex; + + QScopedPointer<QFile> m_traceFile; + quint32 m_frameId; + + Q_DECLARE_PUBLIC(QSystemInformationService) +}; + +class Q_3DCORE_PRIVATE_EXPORT QTaskLogger { +public: + enum Type { + AspectJob, + Submission + }; + + QTaskLogger(QSystemInformationService *service, const JobId &jobId, Type type); + QTaskLogger(QSystemInformationService *service, const quint32 jobType, const quint32 instance, Type type = Submission); + + ~QTaskLogger(); + + void end(qint64 t = 0L); + qint64 restart(); + +private: + QSystemInformationService *m_service; + QSystemInformationServicePrivate::JobRunStats m_stats; + Type m_type; }; } diff --git a/src/logic/callbackjob.cpp b/src/logic/callbackjob.cpp index 5c04d8838..5dfc74f02 100644 --- a/src/logic/callbackjob.cpp +++ b/src/logic/callbackjob.cpp @@ -51,7 +51,7 @@ CallbackJob::CallbackJob() : QAspectJob() , m_logicManager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::Callback, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::Callback, 0) } void CallbackJob::setManager(Manager *manager) diff --git a/src/render/jobs/calcboundingvolumejob.cpp b/src/render/jobs/calcboundingvolumejob.cpp index 9af2f4f38..172c4ddca 100644 --- a/src/render/jobs/calcboundingvolumejob.cpp +++ b/src/render/jobs/calcboundingvolumejob.cpp @@ -354,7 +354,7 @@ CalculateBoundingVolumeJob::CalculateBoundingVolumeJob() : m_manager(nullptr) , m_node(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcBoundingVolume, 0) } void CalculateBoundingVolumeJob::run() diff --git a/src/render/jobs/calcgeometrytrianglevolumes.cpp b/src/render/jobs/calcgeometrytrianglevolumes.cpp index d2b12e09c..eb31a25a6 100644 --- a/src/render/jobs/calcgeometrytrianglevolumes.cpp +++ b/src/render/jobs/calcgeometrytrianglevolumes.cpp @@ -53,7 +53,7 @@ CalcGeometryTriangleVolumes::CalcGeometryTriangleVolumes(const Qt3DCore::QNodeId , m_geometryRendererId(geometryRendererId) , m_manager(manager) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcTriangleVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::CalcTriangleVolume, 0) } void CalcGeometryTriangleVolumes::run() diff --git a/src/render/jobs/expandboundingvolumejob.cpp b/src/render/jobs/expandboundingvolumejob.cpp index 641a5c272..8587634cb 100644 --- a/src/render/jobs/expandboundingvolumejob.cpp +++ b/src/render/jobs/expandboundingvolumejob.cpp @@ -84,7 +84,7 @@ ExpandBoundingVolumeJob::ExpandBoundingVolumeJob() : m_node(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::ExpandBoundingVolume, 0) } void ExpandBoundingVolumeJob::setRoot(Entity *root) diff --git a/src/render/jobs/filterentitybycomponentjob_p.h b/src/render/jobs/filterentitybycomponentjob_p.h index 75e487d7f..cefcdd296 100644 --- a/src/render/jobs/filterentitybycomponentjob_p.h +++ b/src/render/jobs/filterentitybycomponentjob_p.h @@ -74,7 +74,7 @@ public: : Qt3DCore::QAspectJob() , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::EntityComponentTypeFiltering, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::EntityComponentTypeFiltering, 0) } inline void setManager(EntityManager *manager) Q_DECL_NOTHROW { m_manager = manager; } diff --git a/src/render/jobs/filterlayerentityjob.cpp b/src/render/jobs/filterlayerentityjob.cpp index e206ef968..032004422 100644 --- a/src/render/jobs/filterlayerentityjob.cpp +++ b/src/render/jobs/filterlayerentityjob.cpp @@ -58,7 +58,7 @@ FilterLayerEntityJob::FilterLayerEntityJob() : Qt3DCore::QAspectJob() , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LayerFiltering, layerFilterJobCounter++) } diff --git a/src/render/jobs/framecleanupjob.cpp b/src/render/jobs/framecleanupjob.cpp index 17ca60bff..fb63f005b 100644 --- a/src/render/jobs/framecleanupjob.cpp +++ b/src/render/jobs/framecleanupjob.cpp @@ -55,7 +55,7 @@ FrameCleanupJob::FrameCleanupJob() : m_managers(nullptr) , m_root(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrameCleanup, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrameCleanup, 0) } FrameCleanupJob::~FrameCleanupJob() diff --git a/src/render/jobs/frustumcullingjob.cpp b/src/render/jobs/frustumcullingjob.cpp index 0922fb0cb..e22d625df 100644 --- a/src/render/jobs/frustumcullingjob.cpp +++ b/src/render/jobs/frustumcullingjob.cpp @@ -58,7 +58,7 @@ FrustumCullingJob::FrustumCullingJob() , m_manager(nullptr) , m_active(false) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FrustumCulling, 0) } void FrustumCullingJob::run() diff --git a/src/render/jobs/genericlambdajob_p.h b/src/render/jobs/genericlambdajob_p.h index 4d93f0f8d..8cf4276f6 100644 --- a/src/render/jobs/genericlambdajob_p.h +++ b/src/render/jobs/genericlambdajob_p.h @@ -68,7 +68,7 @@ public: : Qt3DCore::QAspectJob() , m_callable(callable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0); + SET_JOB_RUN_STAT_TYPE(this, type, 0) } // QAspectJob interface @@ -111,7 +111,7 @@ public: : Qt3DCore::QAspectJob(*new GenericLambdaJobAndPostFramePrivate<T, U>(postFrameCallable)) , m_runCallable(runCallable) { - SET_JOB_RUN_STAT_TYPE(this, type, 0); + SET_JOB_RUN_STAT_TYPE(this, type, 0) } // QAspectJob interface diff --git a/src/render/jobs/lightgatherer.cpp b/src/render/jobs/lightgatherer.cpp index f4c8dfba8..b79976aef 100644 --- a/src/render/jobs/lightgatherer.cpp +++ b/src/render/jobs/lightgatherer.cpp @@ -53,7 +53,7 @@ LightGatherer::LightGatherer() , m_manager(nullptr) , m_environmentLight(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LightGathering, 0) } void LightGatherer::run() diff --git a/src/render/jobs/loadbufferjob.cpp b/src/render/jobs/loadbufferjob.cpp index c9cbb623d..0f4feb5d4 100644 --- a/src/render/jobs/loadbufferjob.cpp +++ b/src/render/jobs/loadbufferjob.cpp @@ -68,7 +68,7 @@ LoadBufferJob::LoadBufferJob(const HBuffer &handle) , m_handle(handle) , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadBuffer, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadBuffer, 0) } LoadBufferJob::~LoadBufferJob() diff --git a/src/render/jobs/loadgeometryjob.cpp b/src/render/jobs/loadgeometryjob.cpp index 88930038a..2069336cd 100644 --- a/src/render/jobs/loadgeometryjob.cpp +++ b/src/render/jobs/loadgeometryjob.cpp @@ -66,7 +66,7 @@ LoadGeometryJob::LoadGeometryJob(const HGeometryRenderer &handle) , m_handle(handle) , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadGeometry, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadGeometry, 0) } LoadGeometryJob::~LoadGeometryJob() diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp index f858f82e3..be855c608 100644 --- a/src/render/jobs/loadscenejob.cpp +++ b/src/render/jobs/loadscenejob.cpp @@ -63,7 +63,7 @@ LoadSceneJob::LoadSceneJob(const QUrl &source, Qt3DCore::QNodeId sceneComponent) , m_sceneComponent(sceneComponent) , m_managers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::LoadScene, 0) } void LoadSceneJob::setData(const QByteArray &data) diff --git a/src/render/jobs/sendbuffercapturejob.cpp b/src/render/jobs/sendbuffercapturejob.cpp index 3fa185684..2ccb72337 100644 --- a/src/render/jobs/sendbuffercapturejob.cpp +++ b/src/render/jobs/sendbuffercapturejob.cpp @@ -69,7 +69,7 @@ SendBufferCaptureJob::SendBufferCaptureJob() : Qt3DCore::QAspectJob(*new SendBufferCaptureJobPrivate) , m_nodeManagers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendBufferCapture, 0) } SendBufferCaptureJob::~SendBufferCaptureJob() diff --git a/src/render/jobs/sendrendercapturejob.cpp b/src/render/jobs/sendrendercapturejob.cpp index f622c347a..46b1d9449 100644 --- a/src/render/jobs/sendrendercapturejob.cpp +++ b/src/render/jobs/sendrendercapturejob.cpp @@ -51,7 +51,7 @@ SendRenderCaptureJob::SendRenderCaptureJob() : Qt3DCore::QAspectJob() , m_managers(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendRenderCapture, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::SendRenderCapture, 0) } SendRenderCaptureJob::~SendRenderCaptureJob() diff --git a/src/render/jobs/updateentitylayersjob.cpp b/src/render/jobs/updateentitylayersjob.cpp index 2c5e38364..b8c50c179 100644 --- a/src/render/jobs/updateentitylayersjob.cpp +++ b/src/render/jobs/updateentitylayersjob.cpp @@ -52,7 +52,7 @@ namespace Render { UpdateEntityLayersJob::UpdateEntityLayersJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLayerEntity, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateLayerEntity, 0) } diff --git a/src/render/jobs/updatemeshtrianglelistjob.cpp b/src/render/jobs/updatemeshtrianglelistjob.cpp index 1c61d1c90..4837dcad6 100644 --- a/src/render/jobs/updatemeshtrianglelistjob.cpp +++ b/src/render/jobs/updatemeshtrianglelistjob.cpp @@ -60,7 +60,7 @@ namespace Render { UpdateMeshTriangleListJob::UpdateMeshTriangleListJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateMeshTriangleList, 0) } UpdateMeshTriangleListJob::~UpdateMeshTriangleListJob() diff --git a/src/render/jobs/updateshaderdatatransformjob.cpp b/src/render/jobs/updateshaderdatatransformjob.cpp index c29a827e3..11fe91932 100644 --- a/src/render/jobs/updateshaderdatatransformjob.cpp +++ b/src/render/jobs/updateshaderdatatransformjob.cpp @@ -61,7 +61,7 @@ namespace Render { UpdateShaderDataTransformJob::UpdateShaderDataTransformJob() : m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateShaderDataTransform, 0) } UpdateShaderDataTransformJob::~UpdateShaderDataTransformJob() diff --git a/src/render/jobs/updateskinningpalettejob.cpp b/src/render/jobs/updateskinningpalettejob.cpp index 0f5d3d6d6..b77707f15 100644 --- a/src/render/jobs/updateskinningpalettejob.cpp +++ b/src/render/jobs/updateskinningpalettejob.cpp @@ -50,7 +50,7 @@ UpdateSkinningPaletteJob::UpdateSkinningPaletteJob() , m_nodeManagers(nullptr) , m_root() { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateSkinningPalette, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateSkinningPalette, 0) } UpdateSkinningPaletteJob::~UpdateSkinningPaletteJob() diff --git a/src/render/jobs/updatetreeenabledjob.cpp b/src/render/jobs/updatetreeenabledjob.cpp index 5c6f2b378..22d6f6083 100644 --- a/src/render/jobs/updatetreeenabledjob.cpp +++ b/src/render/jobs/updatetreeenabledjob.cpp @@ -73,7 +73,7 @@ UpdateTreeEnabledJob::UpdateTreeEnabledJob() , m_node(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTreeEnabled, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTreeEnabled, 0) } void UpdateTreeEnabledJob::setRoot(Entity *root) diff --git a/src/render/jobs/updateworldtransformjob.cpp b/src/render/jobs/updateworldtransformjob.cpp index d72c0a3a8..e3c8077f4 100644 --- a/src/render/jobs/updateworldtransformjob.cpp +++ b/src/render/jobs/updateworldtransformjob.cpp @@ -109,7 +109,7 @@ UpdateWorldTransformJob::UpdateWorldTransformJob() , m_node(nullptr) , m_manager(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateTransform, 0) } void UpdateWorldTransformJob::setRoot(Entity *root) diff --git a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp index 342fd3dad..d2a01eef4 100644 --- a/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp +++ b/src/render/renderers/opengl/jobs/filtercompatibletechniquejob.cpp @@ -53,7 +53,7 @@ FilterCompatibleTechniqueJob::FilterCompatibleTechniqueJob() : m_manager(nullptr) , m_renderer(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::FilterCompatibleTechniques, 0); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::FilterCompatibleTechniques, 0) } void FilterCompatibleTechniqueJob::setManager(TechniqueManager *manager) diff --git a/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp b/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp index 5e56e817f..e1f8aa403 100644 --- a/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp +++ b/src/render/renderers/opengl/jobs/materialparametergathererjob.cpp @@ -63,7 +63,7 @@ MaterialParameterGathererJob::MaterialParameterGathererJob() , m_techniqueFilter(nullptr) , m_renderPassFilter(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::MaterialParameterGathering, materialParameterGathererCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::MaterialParameterGathering, materialParameterGathererCounter++) } // TechniqueFilter / RenderPassFilter diff --git a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp index 6d6ae7853..5fc2395d3 100644 --- a/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp +++ b/src/render/renderers/opengl/jobs/renderviewcommandupdaterjob.cpp @@ -60,7 +60,7 @@ RenderViewCommandUpdaterJob::RenderViewCommandUpdaterJob() , m_renderer(nullptr) , m_renderables(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderCommandUpdater, renderViewInstanceCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderCommandUpdater, renderViewInstanceCounter++) } void RenderViewCommandUpdaterJob::run() diff --git a/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp b/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp index 7bf55be40..f0f72803c 100644 --- a/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp +++ b/src/render/renderers/opengl/jobs/renderviewinitializerjob.cpp @@ -65,7 +65,7 @@ RenderViewInitializerJob::RenderViewInitializerJob() , m_index(0) , m_renderView(nullptr) { - SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderView, renderViewInstanceCounter++); + SET_JOB_RUN_STAT_TYPE(this, JobTypes::RenderView, renderViewInstanceCounter++) } RenderViewInitializerJob::~RenderViewInitializerJob() diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 3ab5be6cc..df2517018 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -99,6 +99,8 @@ #include <Qt3DCore/private/qeventfilterservice_p.h> #include <Qt3DCore/private/qabstractaspectjobmanager_p.h> #include <Qt3DCore/private/qaspectmanager_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p.h> +#include <Qt3DCore/private/qsysteminformationservice_p_p.h> #if QT_CONFIG(qt3d_profile_jobs) #include <Qt3DCore/private/aspectcommanddebugger_p.h> @@ -752,19 +754,12 @@ void Renderer::doRender(bool swapBuffers) // RenderQueue is complete (but that means it may be of size 0) if (canSubmit && (queueIsComplete && !queueIsEmpty)) { const QVector<Render::RenderView *> renderViews = m_renderQueue->nextFrameQueue(); - -#if QT_CONFIG(qt3d_profile_jobs) - // Save start of frame - JobRunStats submissionStatsPart1; - JobRunStats submissionStatsPart2; - submissionStatsPart1.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart1; - submissionStatsPart1.jobId.typeAndInstance[1] = 0; - submissionStatsPart1.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); - submissionStatsPart1.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - submissionStatsPart2.jobId.typeAndInstance[0] = JobTypes::FrameSubmissionPart2; - submissionStatsPart2.jobId.typeAndInstance[1] = 0; - submissionStatsPart2.threadId = reinterpret_cast<quint64>(QThread::currentThreadId()); -#endif + QTaskLogger submissionStatsPart1(m_services->systemInformation(), + {JobTypes::FrameSubmissionPart1, 0}, + QTaskLogger::Submission); + QTaskLogger submissionStatsPart2(m_services->systemInformation(), + {JobTypes::FrameSubmissionPart2, 0}, + QTaskLogger::Submission); if (canRender()) { { // Scoped to destroy surfaceLock @@ -797,15 +792,11 @@ void Renderer::doRender(bool swapBuffers) m_vsyncFrameAdvanceService->proceedToNextFrame(); hasCleanedQueueAndProceeded = true; -#if QT_CONFIG(qt3d_profile_jobs) - if (preprocessingComplete) { - submissionStatsPart2.startTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - submissionStatsPart1.endTime = submissionStatsPart2.startTime; - } -#endif // Only try to submit the RenderViews if the preprocessing was successful // This part of the submission is happening in parallel to the RV building for the next frame if (preprocessingComplete) { + submissionStatsPart1.end(submissionStatsPart2.restart()); + // 3) Submit the render commands for frame n (making sure we never reference something that could be changing) // Render using current device state and renderer configuration submissionData = submitRenderViews(renderViews); @@ -823,25 +814,12 @@ void Renderer::doRender(bool swapBuffers) // Delete all the RenderViews which will clear the allocators // that were used for their allocation qDeleteAll(renderViews); - -#if QT_CONFIG(qt3d_profile_jobs) - if (preprocessingComplete) { - // Save submission elapsed time - submissionStatsPart2.endTime = QThreadPooler::m_jobsStatTimer.nsecsElapsed(); - // Note this is safe since proceedToNextFrame is the one going to trigger - // the write to the file, and this is performed after this step - Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart1); - Qt3DCore::QThreadPooler::addSubmissionLogStatsEntry(submissionStatsPart2); - Profiling::GLTimeRecorder::writeResults(); - } -#endif } // If hasCleanedQueueAndProceeded isn't true this implies that something went wrong // with the rendering and/or the renderqueue is incomplete from some reason // or alternatively it could be complete but empty (RenderQueue of size 0) - if (!hasCleanedQueueAndProceeded) { // RenderQueue was full but something bad happened when // trying to render it and therefore proceedToNextFrame was not called diff --git a/tests/auto/core/qservicelocator/tst_qservicelocator.cpp b/tests/auto/core/qservicelocator/tst_qservicelocator.cpp index cde9834b4..04e6881aa 100644 --- a/tests/auto/core/qservicelocator/tst_qservicelocator.cpp +++ b/tests/auto/core/qservicelocator/tst_qservicelocator.cpp @@ -54,9 +54,6 @@ public: DummySystemInfoService() : QSystemInformationService(QStringLiteral("Dummy System Information Service")) {} - - QStringList aspectNames() const final { return QStringList(); } - int threadPoolThreadCount() const final { return 4; } }; @@ -90,8 +87,8 @@ void tst_QServiceLocator::defaultServices() QSystemInformationService *sysInfo = locator.systemInformation(); QVERIFY(sysInfo != nullptr); - QVERIFY(sysInfo->description() == QStringLiteral("Null System Information Service")); - QVERIFY(sysInfo->threadPoolThreadCount() == 0); + QVERIFY(sysInfo->description() == QStringLiteral("Default System Information Service")); + QVERIFY(sysInfo->threadPoolThreadCount() != 0); } void tst_QServiceLocator::addRemoveDefaultService() @@ -105,7 +102,6 @@ void tst_QServiceLocator::addRemoveDefaultService() // Get the service from the locator and check it works as expected QSystemInformationService *service = locator.systemInformation(); QVERIFY(service == dummy.data()); - QVERIFY(service->threadPoolThreadCount() == 4); // Ensure the other default services work QOpenGLInformationService *glInfo = locator.openGLInformation(); @@ -118,7 +114,7 @@ void tst_QServiceLocator::addRemoveDefaultService() QVERIFY(locator.serviceCount() == QServiceLocator::DefaultServiceCount); // Check the dummy service still exists - QVERIFY(dummy->threadPoolThreadCount() == 4); + QVERIFY(!dummy.isNull()); } void tst_QServiceLocator::addRemoveUserService() @@ -138,8 +134,8 @@ void tst_QServiceLocator::addRemoveUserService() // Ensure the default services work QSystemInformationService *sysInfo = locator.systemInformation(); QVERIFY(sysInfo != nullptr); - QVERIFY(sysInfo->description() == QStringLiteral("Null System Information Service")); - QVERIFY(sysInfo->threadPoolThreadCount() == 0); + QVERIFY(sysInfo->description() == QStringLiteral("Default System Information Service")); + QVERIFY(sysInfo->threadPoolThreadCount() != 0); // Remove custom service locator.unregisterServiceProvider(dummy->type()); diff --git a/tests/auto/core/threadpooler/tst_threadpooler.cpp b/tests/auto/core/threadpooler/tst_threadpooler.cpp index cfe3480ee..289f0b103 100644 --- a/tests/auto/core/threadpooler/tst_threadpooler.cpp +++ b/tests/auto/core/threadpooler/tst_threadpooler.cpp @@ -182,7 +182,7 @@ void massTestFunction(QVector3D *data) void tst_ThreadPooler::initTestCase() { - m_jobManager = new JobManager(this); + m_jobManager = new JobManager(nullptr); } void tst_ThreadPooler::cleanupTestCase() |