diff options
author | Pasi Keränen <pasi.keranen@qt.io> | 2018-10-31 14:43:14 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-11-13 12:33:03 +0000 |
commit | dd682ac0c58cf0298d565cb8d567de6a63917241 (patch) | |
tree | ae8cf4a7d1bd5185a3f0ae7f5bcf77213a40a953 | |
parent | 6f2129c53b20f47e52558a511b2263d2e1b9c26f (diff) |
macOS: Implement CPU usage profiler reporting
Task-number: QT3DS-2586
Change-Id: Icc9017acf9222853f6345612906288cf4fd79348
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r-- | src/runtime/q3dsprofiler.cpp | 91 | ||||
-rw-r--r-- | src/runtime/q3dsprofiler_p.h | 12 | ||||
-rw-r--r-- | src/runtime/q3dsprofilerhelper_mac.mm | 48 | ||||
-rw-r--r-- | src/runtime/q3dsprofilerhelper_mac_p.h | 64 | ||||
-rw-r--r-- | src/runtime/runtime.pro | 8 |
5 files changed, 218 insertions, 5 deletions
diff --git a/src/runtime/q3dsprofiler.cpp b/src/runtime/q3dsprofiler.cpp index 8303498..727229a 100644 --- a/src/runtime/q3dsprofiler.cpp +++ b/src/runtime/q3dsprofiler.cpp @@ -45,6 +45,7 @@ #ifdef Q_OS_MACOS #include <mach/mach_types.h> #include <mach/mach.h> +#include <sys/sysctl.h> #endif QT_BEGIN_NAMESPACE @@ -263,8 +264,6 @@ float Q3DSProfiler::cpuLoadForCurrentProcess() m_lastUserTimeSys = userTimeSys; m_lastKernelTimeProc = kernelTimeProc; m_lastUserTimeProc = userTimeProc; - - return m_lastCpuLoad; #elif defined(Q_OS_LINUX) if (!m_numCpus) { QFile f(QLatin1String("/proc/cpuinfo")); @@ -291,10 +290,81 @@ float Q3DSProfiler::cpuLoadForCurrentProcess() m_lastTimestamp = timestamp; m_lastKernel = processTimes.tms_stime; m_lastUser = processTimes.tms_utime; - return m_lastCpuLoad; -#else - return m_lastCpuLoad; +#elif defined(Q_OS_MACOS) + // Get thread times + mach_port_t task = mach_task_self(); + task_thread_times_info threadTimes = {}; + mach_msg_type_number_t outCount = TASK_THREAD_TIMES_INFO_COUNT; + + kern_return_t retVal = task_info(task, TASK_THREAD_TIMES_INFO, + task_info_t(&threadTimes), &outCount); + if (retVal != KERN_SUCCESS) + return m_lastCpuLoad; + + // Get task info + mach_task_basic_info_data_t taskInfo = {}; + outCount = MACH_TASK_BASIC_INFO_COUNT; + retVal = task_info(task, MACH_TASK_BASIC_INFO, + task_info_t(&taskInfo), &outCount); + + if (retVal != KERN_SUCCESS) + return m_lastCpuLoad; + + struct timeval userTimeVal, systemTimeVal, totalTimeVal; + + // Thread info contains alive time + userTimeVal.tv_sec = threadTimes.user_time.seconds; + userTimeVal.tv_usec = threadTimes.user_time.microseconds; + systemTimeVal.tv_sec = threadTimes.system_time.seconds; + systemTimeVal.tv_usec = threadTimes.system_time.microseconds; + + // Add user time and system time to total time + timeradd(&userTimeVal, &systemTimeVal, &totalTimeVal); + + // Task info has terminated time + userTimeVal.tv_sec = taskInfo.user_time.seconds; + userTimeVal.tv_usec = taskInfo.user_time.microseconds; + systemTimeVal.tv_sec = taskInfo.system_time.seconds; + systemTimeVal.tv_usec = taskInfo.system_time.microseconds; + + // Add user time and system time to total time + timeradd(&userTimeVal, &totalTimeVal, &totalTimeVal); + timeradd(&systemTimeVal, &totalTimeVal, &totalTimeVal); + + // Get current time + struct timeval now; + int error = gettimeofday(&now, nullptr); + if (error) + return m_lastCpuLoad; + + // Convert everything to microseconds + qint64 timestamp = timeValToMicroseconds(now); + qint64 totalTaskTime = timeValToMicroseconds(totalTimeVal); + + // On first execution just store the current values + if (m_lastTimestamp == 0) { + m_lastTimestamp = timestamp; + m_lastTaskTime = totalTaskTime; + return m_lastCpuLoad; + } + + // Calculate percentage of CPU time this task used over delta time + qint64 taskDeltaTime = totalTaskTime - m_lastTaskTime; + qint64 totalDeltaTime = timestamp - m_lastTimestamp; + + if (totalDeltaTime == 0) + return m_lastCpuLoad; + + m_lastTimestamp = timestamp; + m_lastTaskTime = totalTaskTime; + + m_lastCpuLoad = (taskDeltaTime * 100.f) + / float(totalDeltaTime) + / float(m_macOSProfiler.numActiveProcessors()); + #endif + + return m_lastCpuLoad; } QPair<qint64, qint64> Q3DSProfiler::memUsageForCurrentProcess() @@ -358,4 +428,15 @@ QPair<qint64, qint64> Q3DSProfiler::memUsageForCurrentProcess() return m_lastMemUsage; } +#if defined(Q_OS_MACOS) +qint64 Q3DSProfiler::timeValToMicroseconds(const struct timeval& timeVal) +{ + static const int microsecondsPerSecond = 1000000; + qint64 retVal = timeVal.tv_sec; + retVal *= microsecondsPerSecond; + retVal += timeVal.tv_usec; + return retVal; +} +#endif + QT_END_NAMESPACE diff --git a/src/runtime/q3dsprofiler_p.h b/src/runtime/q3dsprofiler_p.h index 732a5fb..7a65f45 100644 --- a/src/runtime/q3dsprofiler_p.h +++ b/src/runtime/q3dsprofiler_p.h @@ -48,6 +48,10 @@ #include <QHash> #include <QSet> +#if defined(Q_OS_MACOS) +#include "q3dsprofilerhelper_mac_p.h" +#endif + QT_BEGIN_NAMESPACE class Q3DSSceneManager; @@ -156,6 +160,10 @@ public: QPair<qint64, qint64> memUsageForCurrentProcess(); private: +#if defined(Q_OS_MACOS) + qint64 timeValToMicroseconds(const struct timeval& timeVal); +#endif + bool m_enabled = false; // disabled by default, profiling is opt-in QVector<FrameData> m_frameData; QMultiMap<ObjectType, ObjectData> m_objectData; @@ -190,6 +198,10 @@ private: qint64 m_lastTimestamp = 0; qint64 m_lastKernel = 0; qint64 m_lastUser = 0; +#elif defined(Q_OS_MACOS) + qint64 m_lastTimestamp = 0; + qint64 m_lastTaskTime = 0; + Q3DSProfilerHelperMacOS m_macOSProfiler; #endif }; diff --git a/src/runtime/q3dsprofilerhelper_mac.mm b/src/runtime/q3dsprofilerhelper_mac.mm new file mode 100644 index 0000000..c09bebd --- /dev/null +++ b/src/runtime/q3dsprofilerhelper_mac.mm @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#import <Foundation/Foundation.h> + +#include "q3dsprofilerhelper_mac_p.h" + +QT_BEGIN_NAMESPACE + +Q3DSProfilerHelperMacOS::Q3DSProfilerHelperMacOS() +{ +} + +Q3DSProfilerHelperMacOS::~Q3DSProfilerHelperMacOS() +{ +} + +quint32 Q3DSProfilerHelperMacOS::numActiveProcessors() +{ + return quint32([[NSProcessInfo processInfo] activeProcessorCount]); +} + +QT_END_NAMESPACE diff --git a/src/runtime/q3dsprofilerhelper_mac_p.h b/src/runtime/q3dsprofilerhelper_mac_p.h new file mode 100644 index 0000000..a5bfa57 --- /dev/null +++ b/src/runtime/q3dsprofilerhelper_mac_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** 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 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** 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. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef Q3DSPROFILERMACOS_P_H +#define Q3DSPROFILERMACOS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QVector> +#include <QElapsedTimer> +#include <QMultiMap> +#include <QObject> +#include <QHash> +#include <QSet> + +QT_BEGIN_NAMESPACE + +class Q3DSProfilerHelperMacOS +{ +public: + Q3DSProfilerHelperMacOS(); + ~Q3DSProfilerHelperMacOS(); + + quint32 numActiveProcessors(); +}; + +QT_END_NAMESPACE + +#endif // Q3DSPROFILERMACOS_P_H diff --git a/src/runtime/runtime.pro b/src/runtime/runtime.pro index 3bfc422..98bb424 100644 --- a/src/runtime/runtime.pro +++ b/src/runtime/runtime.pro @@ -81,6 +81,14 @@ HEADERS += \ q3dsviewportsettings_p.h \ q3dsscenepicker_p.h +macos: { +LIBS += -framework Foundation +OBJECTIVE_SOURCES += \ + q3dsprofilerhelper_mac.mm +HEADERS += \ + q3dsprofilerhelper_mac_p.h +} + qtHaveModule(widgets) { QT += widgets SOURCES += \ |