diff --git a/CMakeLists.txt b/CMakeLists.txt index 8190fae6d8e7..ca7342fcc8b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1103,7 +1103,6 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/util/mac.cpp src/util/moc_included_test.cpp src/util/movinginterquartilemean.cpp - src/util/performancetimer.cpp src/util/rangelist.cpp src/util/readaheadsamplebuffer.cpp src/util/ringdelaybuffer.cpp diff --git a/src/analyzer/analyzerebur128.cpp b/src/analyzer/analyzerebur128.cpp index 8b3942ffc728..b3e6ae7cd381 100644 --- a/src/analyzer/analyzerebur128.cpp +++ b/src/analyzer/analyzerebur128.cpp @@ -50,7 +50,7 @@ bool AnalyzerEbur128::processSamples(const CSAMPLE* pIn, SINT count) { VERIFY_OR_DEBUG_ASSERT(m_pState) { return false; } - ScopedTimer t("AnalyzerEbur128::processSamples()"); + ScopedTimer t(u"AnalyzerEbur128::processSamples()"); size_t frames = count / mixxx::kAnalysisChannels; int e = ebur128_add_frames_float(m_pState, pIn, frames); VERIFY_OR_DEBUG_ASSERT(e == EBUR128_SUCCESS) { diff --git a/src/analyzer/analyzergain.cpp b/src/analyzer/analyzergain.cpp index d9823875de76..52192c58daea 100644 --- a/src/analyzer/analyzergain.cpp +++ b/src/analyzer/analyzergain.cpp @@ -37,7 +37,7 @@ void AnalyzerGain::cleanup() { } bool AnalyzerGain::processSamples(const CSAMPLE* pIn, SINT count) { - ScopedTimer t("AnalyzerGain::process()"); + ScopedTimer t(u"AnalyzerGain::process()"); SINT numFrames = count / mixxx::kAnalysisChannels; if (numFrames > static_cast(m_pLeftTempBuffer.size())) { diff --git a/src/coreservices.cpp b/src/coreservices.cpp index dc7e95b98a31..8fc1b4c17d72 100644 --- a/src/coreservices.cpp +++ b/src/coreservices.cpp @@ -110,7 +110,7 @@ CoreServices::CoreServices(const CmdlineArgs& args, QApplication* pApp) m_isInitialized(false) { m_runtime_timer.start(); mixxx::Time::start(); - ScopedTimer t("CoreServices::CoreServices"); + ScopedTimer t(u"CoreServices::CoreServices"); // All this here is running without without start up screen // Defer long initializations to CoreServices::initialize() which is // called after the GUI is initialized @@ -210,7 +210,7 @@ void CoreServices::initialize(QApplication* pApp) { return; } - ScopedTimer t("CoreServices::initialize"); + ScopedTimer t(u"CoreServices::initialize"); VERIFY_OR_DEBUG_ASSERT(SoundSourceProxy::registerProviders()) { qCritical() << "Failed to register any SoundSource providers"; diff --git a/src/engine/channelmixer.cpp b/src/engine/channelmixer.cpp index 664e87e24e7c..694dbc29c040 100644 --- a/src/engine/channelmixer.cpp +++ b/src/engine/channelmixer.cpp @@ -22,7 +22,7 @@ void ChannelMixer::applyEffectsAndMixChannels(const EngineMaster::GainCalculator // D) Mixes the temporary buffer into pOutput // The original channel input buffers are not modified. SampleUtil::clear(pOutput, iBufferSize); - ScopedTimer t("EngineMaster::applyEffectsAndMixChannels"); + ScopedTimer t(u"EngineMaster::applyEffectsAndMixChannels"); for (auto* pChannelInfo : activeChannels) { EngineMaster::GainCache& gainCache = (*channelGainCache)[pChannelInfo->m_index]; CSAMPLE_GAIN oldGain = gainCache.m_gain; @@ -67,7 +67,7 @@ void ChannelMixer::applyEffectsInPlaceAndMixChannels( // A) Applies the calculated gain to the channel buffer, modifying the original input buffer // B) Applies effects to the buffer, modifying the original input buffer // 4. Mix the channel buffers together to make pOutput, overwriting the pOutput buffer from the last engine callback - ScopedTimer t("EngineMaster::applyEffectsInPlaceAndMixChannels"); + ScopedTimer t(u"EngineMaster::applyEffectsInPlaceAndMixChannels"); SampleUtil::clear(pOutput, iBufferSize); for (auto* pChannelInfo : activeChannels) { EngineMaster::GainCache& gainCache = (*channelGainCache)[pChannelInfo->m_index]; diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index e065540135ad..d730aaacb34a 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -815,7 +815,7 @@ void EngineBuffer::slotKeylockEngineChanged(double dIndex) { void EngineBuffer::processTrackLocked( CSAMPLE* pOutput, const int iBufferSize, mixxx::audio::SampleRate sampleRate) { - ScopedTimer t("EngineBuffer::process_pauselock"); + ScopedTimer t(u"EngineBuffer::process_pauselock"); m_trackSampleRateOld = mixxx::audio::SampleRate::fromDouble(m_pTrackSampleRate->get()); m_trackEndPositionOld = getTrackEndPosition(); diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 01c551b1eb5a..afc197488790 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -279,7 +279,7 @@ void EngineMaster::processChannels(int iBufferSize) { m_activeTalkoverChannels.clear(); m_activeChannels.clear(); - //ScopedTimer timer("EngineMaster::processChannels"); + // ScopedTimer timer(u"EngineMaster::processChannels"); EngineChannel* pLeaderChannel = m_pEngineSync->getLeaderChannel(); // Reserve the first place for the master channel which // should be processed first diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp index 17219eca3863..5140e5b39d51 100644 --- a/src/library/dao/trackdao.cpp +++ b/src/library/dao/trackdao.cpp @@ -1374,7 +1374,7 @@ TrackPointer TrackDAO::getTrackById(TrackId trackId) const { // be executed with a lock on the GlobalTrackCache. The GlobalTrackCache // will be locked again after the query has been executed (see below) // and potential race conditions will be resolved. - ScopedTimer t("TrackDAO::getTrackById"); + ScopedTimer t(u"TrackDAO::getTrackById"); QSqlRecord queryRecord; { diff --git a/src/library/scanner/importfilestask.cpp b/src/library/scanner/importfilestask.cpp index 62de43bc0cea..70e2938fa881 100644 --- a/src/library/scanner/importfilestask.cpp +++ b/src/library/scanner/importfilestask.cpp @@ -22,7 +22,7 @@ ImportFilesTask::ImportFilesTask(LibraryScanner* pScanner, } void ImportFilesTask::run() { - ScopedTimer timer("ImportFilesTask::run"); + ScopedTimer timer(u"ImportFilesTask::run"); for (const QFileInfo& fileInfo: m_filesToImport) { // If a flag was raised telling us to cancel the library scan then stop. if (m_scannerGlobal->shouldCancel()) { diff --git a/src/library/scanner/libraryscanner.cpp b/src/library/scanner/libraryscanner.cpp index 693a35eff8b9..f377f2f1e75c 100644 --- a/src/library/scanner/libraryscanner.cpp +++ b/src/library/scanner/libraryscanner.cpp @@ -489,7 +489,7 @@ void LibraryScanner::cancel() { void LibraryScanner::queueTask(ScannerTask* pTask) { //kLogger.debug() << "queueTask" << pTask; - ScopedTimer timer("LibraryScanner::queueTask"); + ScopedTimer timer(u"LibraryScanner::queueTask"); if (m_scannerGlobal.isNull() || m_scannerGlobal->shouldCancel()) { return; } @@ -531,7 +531,7 @@ void LibraryScanner::queueTask(ScannerTask* pTask) { void LibraryScanner::slotDirectoryHashedAndScanned(const QString& directoryPath, bool newDirectory, mixxx::cache_key_t hash) { - ScopedTimer timer("LibraryScanner::slotDirectoryHashedAndScanned"); + ScopedTimer timer(u"LibraryScanner::slotDirectoryHashedAndScanned"); //kLogger.debug() << "sloDirectoryHashedAndScanned" << directoryPath // << newDirectory << hash; @@ -550,7 +550,7 @@ void LibraryScanner::slotDirectoryHashedAndScanned(const QString& directoryPath, } void LibraryScanner::slotDirectoryUnchanged(const QString& directoryPath) { - ScopedTimer timer("LibraryScanner::slotDirectoryUnchanged"); + ScopedTimer timer(u"LibraryScanner::slotDirectoryUnchanged"); //kLogger.debug() << "slotDirectoryUnchanged" << directoryPath; if (m_scannerGlobal) { m_scannerGlobal->addVerifiedDirectory(directoryPath); @@ -560,7 +560,7 @@ void LibraryScanner::slotDirectoryUnchanged(const QString& directoryPath) { void LibraryScanner::slotTrackExists(const QString& trackPath) { //kLogger.debug() << "slotTrackExists" << trackPath; - ScopedTimer timer("LibraryScanner::slotTrackExists"); + ScopedTimer timer(u"LibraryScanner::slotTrackExists"); if (m_scannerGlobal) { m_scannerGlobal->addVerifiedTrack(trackPath); } @@ -568,7 +568,7 @@ void LibraryScanner::slotTrackExists(const QString& trackPath) { void LibraryScanner::slotAddNewTrack(const QString& trackPath) { //kLogger.debug() << "slotAddNewTrack" << trackPath; - ScopedTimer timer("LibraryScanner::addNewTrack"); + ScopedTimer timer(u"LibraryScanner::addNewTrack"); // For statistics tracking and to detect moved tracks TrackPointer pTrack = m_trackDao.addTracksAddFile( trackPath, diff --git a/src/library/scanner/recursivescandirectorytask.cpp b/src/library/scanner/recursivescandirectorytask.cpp index 0d64d9b4a686..df93b6e038dd 100644 --- a/src/library/scanner/recursivescandirectorytask.cpp +++ b/src/library/scanner/recursivescandirectorytask.cpp @@ -20,7 +20,7 @@ RecursiveScanDirectoryTask::RecursiveScanDirectoryTask( } void RecursiveScanDirectoryTask::run() { - ScopedTimer timer("RecursiveScanDirectoryTask::run"); + ScopedTimer timer(u"RecursiveScanDirectoryTask::run"); if (m_scannerGlobal->shouldCancel()) { setSuccess(false); return; diff --git a/src/main.cpp b/src/main.cpp index b6fddc6ef797..9077939267f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -170,6 +170,8 @@ int main(int argc, char * argv[]) { // the main thread. Issue #9130. ErrorDialogHandler::instance(); + PerformanceTimer::debugEnsureClockIsMonotonic(); + #ifdef __APPLE__ Sandbox::checkSandboxed(); #endif diff --git a/src/mixxxmainwindow.cpp b/src/mixxxmainwindow.cpp index 4ac9b3f3607c..f20676970170 100644 --- a/src/mixxxmainwindow.cpp +++ b/src/mixxxmainwindow.cpp @@ -682,7 +682,7 @@ void MixxxMainWindow::slotUpdateWindowTitle(TrackPointer pTrack) { } void MixxxMainWindow::createMenuBar() { - ScopedTimer t("MixxxMainWindow::createMenuBar"); + ScopedTimer t(u"MixxxMainWindow::createMenuBar"); DEBUG_ASSERT(m_pCoreServices->getKeyboardConfig()); m_pMenuBar = make_parented( this, m_pCoreServices->getSettings(), m_pCoreServices->getKeyboardConfig().get()); @@ -696,7 +696,7 @@ void MixxxMainWindow::connectMenuBar() { // This function might be invoked multiple times on startup // so all connections must be unique! - ScopedTimer t("MixxxMainWindow::connectMenuBar"); + ScopedTimer t(u"MixxxMainWindow::connectMenuBar"); connect(this, &MixxxMainWindow::skinLoaded, m_pMenuBar, diff --git a/src/skin/legacy/legacyskinparser.cpp b/src/skin/legacy/legacyskinparser.cpp index 274586b23994..adc6c8b4c6a5 100644 --- a/src/skin/legacy/legacyskinparser.cpp +++ b/src/skin/legacy/legacyskinparser.cpp @@ -328,7 +328,7 @@ Qt::MouseButton LegacySkinParser::parseButtonState(const QDomNode& node, } QWidget* LegacySkinParser::parseSkin(const QString& skinPath, QWidget* pParent) { - ScopedTimer timer("SkinLoader::parseSkin"); + ScopedTimer timer(u"SkinLoader::parseSkin"); qDebug() << "LegacySkinParser loading skin:" << skinPath; m_pContext = std::make_unique(m_pConfig, skinPath + "/skin.xml"); diff --git a/src/skin/skinloader.cpp b/src/skin/skinloader.cpp index 4676da6282b2..06ad3ec53d5b 100644 --- a/src/skin/skinloader.cpp +++ b/src/skin/skinloader.cpp @@ -138,7 +138,7 @@ QString SkinLoader::getDefaultSkinName() const { QWidget* SkinLoader::loadConfiguredSkin(QWidget* pParent, QSet* pSkinCreatedControls, mixxx::CoreServices* pCoreServices) { - ScopedTimer timer("SkinLoader::loadConfiguredSkin"); + ScopedTimer timer(u"SkinLoader::loadConfiguredSkin"); SkinPointer pSkin = getConfiguredSkin(); // If we don't have a skin then fail. This makes sense here, because the diff --git a/src/soundio/sounddevicenetwork.cpp b/src/soundio/sounddevicenetwork.cpp index 17b7d88eff8c..742834df2dba 100644 --- a/src/soundio/sounddevicenetwork.cpp +++ b/src/soundio/sounddevicenetwork.cpp @@ -485,7 +485,7 @@ void SoundDeviceNetwork::callbackProcessClkRef() { m_pSoundManager->readProcess(framesPerBuffer); { - ScopedTimer t("SoundDevicePortAudio::callbackProcess prepare %1", + ScopedTimer t(u"SoundDevicePortAudio::callbackProcess prepare %1", m_deviceId.name); m_pSoundManager->onDeviceOutputCallback(framesPerBuffer); } diff --git a/src/soundio/sounddeviceportaudio.cpp b/src/soundio/sounddeviceportaudio.cpp index b2b1fb297f72..84a32d5a5f0c 100644 --- a/src/soundio/sounddeviceportaudio.cpp +++ b/src/soundio/sounddeviceportaudio.cpp @@ -975,7 +975,7 @@ int SoundDevicePortAudio::callbackProcessClkRef( // Send audio from the soundcard's input off to the SoundManager... if (in) { - ScopedTimer t("SoundDevicePortAudio::callbackProcess input %1", + ScopedTimer t(u"SoundDevicePortAudio::callbackProcess input %1", m_deviceId.debugName()); composeInputBuffer(in, framesPerBuffer, 0, m_inputParams.channelCount); m_pSoundManager->pushInputBuffers(m_audioInputs, framesPerBuffer); @@ -984,13 +984,13 @@ int SoundDevicePortAudio::callbackProcessClkRef( m_pSoundManager->readProcess(framesPerBuffer); { - ScopedTimer t("SoundDevicePortAudio::callbackProcess prepare %1", + ScopedTimer t(u"SoundDevicePortAudio::callbackProcess prepare %1", m_deviceId.debugName()); m_pSoundManager->onDeviceOutputCallback(framesPerBuffer); } if (out) { - ScopedTimer t("SoundDevicePortAudio::callbackProcess output %1", + ScopedTimer t(u"SoundDevicePortAudio::callbackProcess output %1", m_deviceId.debugName()); if (m_outputParams.channelCount <= 0) { diff --git a/src/sources/soundsourcemodplug.cpp b/src/sources/soundsourcemodplug.cpp index 7226a775042a..8a5d8b6900a4 100644 --- a/src/sources/soundsourcemodplug.cpp +++ b/src/sources/soundsourcemodplug.cpp @@ -119,7 +119,7 @@ SoundSourceModPlug::importTrackMetadataAndCoverImage( SoundSource::OpenResult SoundSourceModPlug::tryOpen( OpenMode /*mode*/, const OpenParams& /*config*/) { - ScopedTimer t("SoundSourceModPlug::open()"); + ScopedTimer t(u"SoundSourceModPlug::open()"); // read module file to byte array const QString fileName(getLocalFileName()); diff --git a/src/test/performancetimer_test.cpp b/src/test/performancetimer_test.cpp index 639744726c04..183e688cbbed 100644 --- a/src/test/performancetimer_test.cpp +++ b/src/test/performancetimer_test.cpp @@ -3,6 +3,10 @@ #include "util/performancetimer.h" +TEST(PerformanceTimerTest, ElapsedIsMonotonic) { + ASSERT_TRUE(PerformanceTimer::debugEnsureClockIsMonotonic()); +} + // This test was added because of an signed/unsigned underflow bug that // affected Windows and (presumably) Symbian. // See https://github.com/mixxxdj/mixxx/issues/7397 diff --git a/src/util/battery/battery.cpp b/src/util/battery/battery.cpp index bd2cdee41ae7..cef6b35a035a 100644 --- a/src/util/battery/battery.cpp +++ b/src/util/battery/battery.cpp @@ -1,5 +1,7 @@ #include "util/battery/battery.h" +#include + #include "moc_battery.cpp" // Do not include platform-specific battery implementation unless we are built @@ -15,8 +17,9 @@ #endif #include "util/math.h" -// interval (in ms) of the timer which calls update() -constexpr int kiUpdateInterval = 5000; +using namespace std::chrono_literals; +// interval of the timer which calls update() +static constexpr std::chrono::milliseconds kBatteryUpdateInterval = 5000ms; Battery::Battery(QObject* parent) : QObject(parent), @@ -24,8 +27,8 @@ Battery::Battery(QObject* parent) m_dPercentage(0.0), m_iMinutesLeft(0), m_timer(this) { - connect(&m_timer, &GuiTickTimer::timeout, this, &Battery::update); - m_timer.start(mixxx::Duration::fromMillis(kiUpdateInterval)); + connect(&m_timer, &QTimer::timeout, this, &Battery::update); + m_timer.start(kBatteryUpdateInterval); } Battery* Battery::getBattery(QObject* parent) { diff --git a/src/util/battery/battery.h b/src/util/battery/battery.h index 3e9fdc82fa06..6eef33bc5dd8 100644 --- a/src/util/battery/battery.h +++ b/src/util/battery/battery.h @@ -43,5 +43,5 @@ class Battery : public QObject { int m_iMinutesLeft; private: - GuiTickTimer m_timer; + QTimer m_timer; }; diff --git a/src/util/duration.h b/src/util/duration.h index 4e48beabeebf..a9fc90f24c4a 100644 --- a/src/util/duration.h +++ b/src/util/duration.h @@ -154,6 +154,15 @@ class Duration : public DurationBase { return Duration(nanos); } + static constexpr Duration fromStdDuration( + std::chrono::duration duration) { + return Duration::fromNanos(duration.count()); + } + + constexpr std::chrono::duration toStdDuration() { + return std::chrono::duration(m_durationNanos); + } + static constexpr Duration empty() { return Duration(); } diff --git a/src/util/performancetimer.cpp b/src/util/performancetimer.cpp deleted file mode 100644 index 8f2769cf0c76..000000000000 --- a/src/util/performancetimer.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "performancetimer.h" - -#if defined(Q_OS_MAC) -#include -#include -#include -#elif defined(Q_OS_SYMBIAN) -#include -#include -#include -#include -#elif defined(Q_OS_UNIX) -#include -#include -#include -#elif defined(Q_OS_WIN) -#include -#endif - -// mac/unix code heavily copied from QElapsedTimer - - -////////////////////////////// Mac ////////////////////////////// -#if defined(Q_OS_MAC) - -static mach_timebase_info_data_t info = {0,0}; -static qint64 absoluteToNSecs(qint64 cpuTime) -{ - if (info.denom == 0) - mach_timebase_info(&info); - qint64 nsecs = cpuTime * info.numer / info.denom; - return nsecs; -} - -void PerformanceTimer::start() -{ - t1 = mach_absolute_time(); -} - -mixxx::Duration PerformanceTimer::elapsed() const -{ - uint64_t cpu_time = mach_absolute_time(); - return mixxx::Duration::fromNanos(absoluteToNSecs(cpu_time - t1)); -} - -mixxx::Duration PerformanceTimer::restart() -{ - qint64 start; - start = t1; - t1 = mach_absolute_time(); - return mixxx::Duration::fromNanos(absoluteToNSecs(t1-start)); -} - -mixxx::Duration PerformanceTimer::difference(const PerformanceTimer& timer) const -{ - return mixxx::Duration::fromNanos(absoluteToNSecs(t1 - timer.t1)); -} - -////////////////////////////// Symbian ////////////////////////////// -#elif defined(Q_OS_SYMBIAN) - -static qint64 getTimeFromTick(qint64 elapsed) -{ - static TInt freq = 0; - if (!freq) - HAL::Get(HALData::EFastCounterFrequency, freq); - - return (elapsed * 1000000000) / freq; -} - -void PerformanceTimer::start() -{ - t1 = User::FastCounter(); -} - -mixxx::Duration PerformanceTimer::elapsed() const -{ - return mixxx::Duration::fromNanos(getTimeFromTick(User::FastCounter() - t1)); -} - -mixxx::Duration PerformanceTimer::restart() -{ - qint64 start; - start = t1; - t1 = User::FastCounter(); - return mixxx::Duration::fromNanos(getTimeFromTick(t1 - start)); -} - -mixxx::Duration PerformanceTimer::difference(const PerformanceTimer& timer) const -{ - return mixxx::Duration::fromNanos(getTimeFromTick(t1 - timer.t1)); -} - -////////////////////////////// Unix ////////////////////////////// -#elif defined(Q_OS_UNIX) - -#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED) -// turn off the monotonic clock -# ifdef _POSIX_MONOTONIC_CLOCK -# undef _POSIX_MONOTONIC_CLOCK -# endif -# define _POSIX_MONOTONIC_CLOCK -1 -#endif - -#if (_POSIX_MONOTONIC_CLOCK-0 != 0) -static const bool monotonicClockChecked = true; -static const bool monotonicClockAvailable = _POSIX_MONOTONIC_CLOCK > 0; -#else -static int monotonicClockChecked = false; -static int monotonicClockAvailable = false; -#endif - -#ifdef Q_CC_GNU -# define is_likely(x) __builtin_expect((x), 1) -#else -# define is_likely(x) (x) -#endif -#define load_acquire(x) ((volatile const int&)(x)) -#define store_release(x,v) ((volatile int&)(x) = (v)) - -static void unixCheckClockType() -{ -#if (_POSIX_MONOTONIC_CLOCK-0 == 0) - if (is_likely(load_acquire(monotonicClockChecked))) { - return; - } - -# if defined(_SC_MONOTONIC_CLOCK) - // detect if the system support monotonic timers - long x = sysconf(_SC_MONOTONIC_CLOCK); - store_release(monotonicClockAvailable, x >= 200112L); -# endif - - store_release(monotonicClockChecked, true); -#endif -} - -static inline void do_gettime(qint64 *sec, qint64 *frac) -{ -#if (_POSIX_MONOTONIC_CLOCK-0 >= 0) - unixCheckClockType(); - if (is_likely(monotonicClockAvailable)) { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - *sec = ts.tv_sec; - *frac = ts.tv_nsec; - return; - } -#endif - *sec = 0; - *frac = 0; -} - -void PerformanceTimer::start() -{ - do_gettime(&t1, &t2); -} - -mixxx::Duration PerformanceTimer::elapsed() const -{ - qint64 sec, frac; - do_gettime(&sec, &frac); - sec = sec - t1; - frac = frac - t2; - - return mixxx::Duration::fromNanos(sec * Q_INT64_C(1000000000) + frac); -} - -mixxx::Duration PerformanceTimer::restart() -{ - qint64 sec, frac; - sec = t1; - frac = t2; - do_gettime(&t1, &t2); - sec = t1 - sec; - frac = t2 - frac; - return mixxx::Duration::fromNanos(sec * Q_INT64_C(1000000000) + frac); -} - -mixxx::Duration PerformanceTimer::difference(const PerformanceTimer& timer) const -{ - qint64 sec, frac; - sec = t1 - timer.t1; - frac = t2 - timer.t2; - return mixxx::Duration::fromNanos(sec * Q_INT64_C(1000000000) + frac); -} - -////////////////////////////// Windows ////////////////////////////// -#elif defined(Q_OS_WIN) - -static qint64 getTimeFromTick(qint64 elapsed) -{ - static LARGE_INTEGER freq = {{ 0, 0 }}; - if (!freq.QuadPart) - QueryPerformanceFrequency(&freq); - return 1000000000 * elapsed / freq.QuadPart; -} - -void PerformanceTimer::start() -{ - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - t1 = li.QuadPart; -} - -mixxx::Duration PerformanceTimer::elapsed() const -{ - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - return mixxx::Duration::fromNanos(getTimeFromTick(li.QuadPart - t1)); -} - -mixxx::Duration PerformanceTimer::restart() -{ - LARGE_INTEGER li; - qint64 start; - start = t1; - QueryPerformanceCounter(&li); - t1 = li.QuadPart; - return mixxx::Duration::fromNanos(getTimeFromTick(t1 - start)); -} - -mixxx::Duration PerformanceTimer::difference(const PerformanceTimer& timer) const -{ - return mixxx::Duration::fromNanos(getTimeFromTick(t1 - timer.t1)); -} - -////////////////////////////// Default ////////////////////////////// -#else - -// default implementation (no hi-perf timer) does nothing -void PerformanceTimer::start() -{ -} - -mixxx::Duration PerformanceTimer::elapsed() const -{ - return mixxx::Duration::fromNanos(0); -} - -mixxx::Duration PerformanceTimer::restart() const -{ - return mixxx::Duration::fromNanos(0); -} - -mixxx::Duration PerformanceTimer::difference(const PerformanceTimer& timer) const -{ - return mixxx::Duration::fromNanos(0); -} - -#endif diff --git a/src/util/performancetimer.h b/src/util/performancetimer.h index 2625d5010a61..8d0286667a52 100644 --- a/src/util/performancetimer.h +++ b/src/util/performancetimer.h @@ -1,75 +1,42 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - #pragma once - -// -// This is a fork of QPerformanceTimer just without the Q prefix -// To fix interface changes issues in different QT versions -// Added restart() function. -// Returns time in nanosecond resolution. -// - -#include +#include #include "util/duration.h" -class PerformanceTimer -{ -public: - PerformanceTimer() { - t1 = 0; -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - t2 = 0; -#endif +class PerformanceTimer { + public: + PerformanceTimer() + : m_elapsedTimer() { + } + + // call this once at startup to ensure that the QElapsedTimer is monotonic + static bool debugEnsureClockIsMonotonic() { + DEBUG_ASSERT(QElapsedTimer::isMonotonic()); + return QElapsedTimer::isMonotonic(); }; - void start(); - mixxx::Duration elapsed() const; - mixxx::Duration restart(); - mixxx::Duration difference(const PerformanceTimer& timer) const; + void start() { + m_elapsedTimer.start(); + } + + mixxx::Duration elapsed() const { + return mixxx::Duration::fromNanos(m_elapsedTimer.nsecsElapsed()); + } + + mixxx::Duration restart() { + const mixxx::Duration elapsedNs = elapsed(); + m_elapsedTimer.restart(); + return elapsedNs; + } + + mixxx::Duration difference(const PerformanceTimer& timer) const { + return timer.elapsed() - elapsed(); + } + + bool running() const { + return m_elapsedTimer.isValid(); + } -private: - qint64 t1; -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) - qint64 t2; -#endif + private: + QElapsedTimer m_elapsedTimer; }; diff --git a/src/util/stat.h b/src/util/stat.h index 15a5de9ce351..5ed57bd932c9 100644 --- a/src/util/stat.h +++ b/src/util/stat.h @@ -44,6 +44,8 @@ class Stat { } } + // TODO make this an enum class for improved typesafety and issues with + // ambiguous overloads. enum ComputeTypes { NONE = 0x0000, // O(1) in time and space. @@ -74,7 +76,7 @@ class Stat { // Used for marking stats recorded in BASE mode. STATS_BASE = 0x1000, }; - typedef int ComputeFlags; + Q_DECLARE_FLAGS(ComputeFlags, ComputeTypes); static Experiment::Mode modeFromFlags(ComputeFlags flags) { if (flags & Stat::STATS_EXPERIMENT) { @@ -132,6 +134,8 @@ class Stat { double) = delete; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(Stat::ComputeFlags); + QDebug operator<<(QDebug dbg, const Stat &stat); struct StatReport { diff --git a/src/util/threadcputimer.h b/src/util/threadcputimer.h index c93ec6605fbc..bb8c3922f3e5 100644 --- a/src/util/threadcputimer.h +++ b/src/util/threadcputimer.h @@ -1,7 +1,6 @@ #pragma once #include "util/duration.h" -#include "util/performancetimer.h" class ThreadCpuTimer { public: diff --git a/src/util/timer.cpp b/src/util/timer.cpp index 335c99967647..30c29d647199 100644 --- a/src/util/timer.cpp +++ b/src/util/timer.cpp @@ -5,19 +5,17 @@ #include "util/time.h" #include "waveform/guitick.h" -Timer::Timer(const QString& key, Stat::ComputeFlags compute) - : m_key(key), - m_compute(Stat::experimentFlags(compute)), - m_running(false) { +Timer::Timer(QString key, Stat::ComputeFlags compute) + : m_key(std::move(key)), + m_compute(Stat::experimentFlags(compute)) { } void Timer::start() { - m_running = true; m_time.start(); } mixxx::Duration Timer::restart(bool report) { - if (m_running) { + if (m_time.running()) { mixxx::Duration elapsed = m_time.restart(); if (report) { // Ignore the report if it crosses the experiment boundary. @@ -46,68 +44,3 @@ mixxx::Duration Timer::elapsed(bool report) { } return elapsedTime; } - - -SuspendableTimer::SuspendableTimer(const QString& key, - Stat::ComputeFlags compute) - : Timer(key, compute) { -} - -void SuspendableTimer::start() { - m_leapTime = mixxx::Duration::fromSeconds(0); - Timer::start(); -} - -mixxx::Duration SuspendableTimer::suspend() { - m_leapTime += m_time.elapsed(); - m_running = false; - return m_leapTime; -} - -void SuspendableTimer::go() { - Timer::start(); -} - -mixxx::Duration SuspendableTimer::elapsed(bool report) { - m_leapTime += m_time.elapsed(); - if (report) { - // Ignore the report if it crosses the experiment boundary. - Experiment::Mode oldMode = Stat::modeFromFlags(m_compute); - if (oldMode == Experiment::mode()) { - Stat::track(m_key, Stat::DURATION_NANOSEC, m_compute, - m_leapTime.toIntegerNanos()); - } - } - return m_leapTime; -} - -GuiTickTimer::GuiTickTimer(QObject* pParent) - : QObject(pParent), - m_pGuiTick(make_parented( - "[Master]", "guiTickTime", this)), - m_bActive(false) { -} - -void GuiTickTimer::start(mixxx::Duration duration) { - m_pGuiTick->connectValueChanged(this, &GuiTickTimer::slotGuiTick); - m_interval = duration; - m_lastUpdate = mixxx::Duration::fromSeconds(0); - m_bActive = true; -} - -void GuiTickTimer::stop() { - m_pGuiTick->disconnect(); - m_bActive = false; - m_interval = mixxx::Duration::fromSeconds(0); - m_lastUpdate = mixxx::Duration::fromSeconds(0); -} - -void GuiTickTimer::slotGuiTick(double) { - if (m_bActive) { - auto time = mixxx::Time::elapsed(); - if (time - m_lastUpdate >= m_interval) { - m_lastUpdate = time; - emit timeout(); - } - } -} diff --git a/src/util/timer.h b/src/util/timer.h index 8be1adf939f7..51948b0d3ef2 100644 --- a/src/util/timer.h +++ b/src/util/timer.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include "control/controlproxy.h" #include "util/cmdlineargs.h" @@ -9,7 +11,7 @@ #include "util/performancetimer.h" #include "util/stat.h" -const Stat::ComputeFlags kDefaultComputeFlags = Stat::COUNT | Stat::SUM | Stat::AVERAGE | +static constexpr Stat::ComputeFlags kDefaultComputeFlags = Stat::COUNT | Stat::SUM | Stat::AVERAGE | Stat::MAX | Stat::MIN | Stat::SAMPLE_VARIANCE; // A Timer that is instrumented for reporting elapsed times to StatsManager @@ -17,8 +19,8 @@ const Stat::ComputeFlags kDefaultComputeFlags = Stat::COUNT | Stat::SUM | Stat:: // computed for the times. class Timer { public: - Timer(const QString& key, - Stat::ComputeFlags compute = kDefaultComputeFlags); + Timer(QString key, + Stat::ComputeFlags compute = kDefaultComputeFlags); void start(); // Restart the timer returning the time duration since it was last @@ -33,103 +35,58 @@ class Timer { protected: QString m_key; Stat::ComputeFlags m_compute; - bool m_running; PerformanceTimer m_time; }; -class SuspendableTimer : public Timer { - public: - SuspendableTimer(const QString& key, - Stat::ComputeFlags compute = kDefaultComputeFlags); - void start(); - mixxx::Duration suspend(); - void go(); - mixxx::Duration elapsed(bool report); - - private: - mixxx::Duration m_leapTime; -}; - +// TODO: replace with std::experimental::scope_exit once stabilized class ScopedTimer { public: - ScopedTimer(const char* key, int i, - Stat::ComputeFlags compute = kDefaultComputeFlags) - : m_pTimer(NULL), - m_cancel(false) { - if (CmdlineArgs::Instance().getDeveloper()) { - initialize(QString(key), QString::number(i), compute); - } + ScopedTimer(QStringView key, + Stat::ComputeFlags compute = kDefaultComputeFlags) + : ScopedTimer(key, QStringView(), compute) { } - - ScopedTimer(const char* key, const char *arg = NULL, - Stat::ComputeFlags compute = kDefaultComputeFlags) - : m_pTimer(NULL), - m_cancel(false) { - if (CmdlineArgs::Instance().getDeveloper()) { - initialize(QString(key), arg ? QString(arg) : QString(), compute); - } + ScopedTimer(QStringView key, + int i, + Stat::ComputeFlags compute = kDefaultComputeFlags) + : ScopedTimer(key, + CmdlineArgs::Instance().getDeveloper() + ? QString::number(i) + : QStringView(), + compute) { } - ScopedTimer(const char* key, const QString& arg, - Stat::ComputeFlags compute = kDefaultComputeFlags) - : m_pTimer(NULL), - m_cancel(false) { - if (CmdlineArgs::Instance().getDeveloper()) { - initialize(QString(key), arg, compute); + ScopedTimer(QStringView key, QStringView arg, Stat::ComputeFlags compute = kDefaultComputeFlags) + : m_maybeTimer(std::nullopt) { + if (!CmdlineArgs::Instance().getDeveloper()) { + return; } +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + QString strKey = arg.isEmpty() ? key.toString() : key.arg(arg); +#else + QString strKey = arg.isEmpty() ? key.toString() : key.toString().arg(arg); +#endif + m_maybeTimer = std::make_optional(std::move(strKey), compute); + m_maybeTimer->start(); } - virtual ~ScopedTimer() { - if (m_pTimer) { - if (!m_cancel) { - m_pTimer->elapsed(true); - } - m_pTimer->~Timer(); + ~ScopedTimer() noexcept { + if (m_maybeTimer) { + m_maybeTimer->elapsed(true); } } - inline void initialize(const QString& key, const QString& arg, - Stat::ComputeFlags compute = kDefaultComputeFlags) { - QString strKey; - if (arg.isEmpty()) { - strKey = key; - } else { - strKey = key.arg(arg); - } - m_pTimer = new(m_timerMem) Timer(strKey, compute); - m_pTimer->start(); - } + ScopedTimer(const ScopedTimer&) = delete; + ScopedTimer& operator=(const ScopedTimer&) = delete; + + ScopedTimer(ScopedTimer&&) = default; + ScopedTimer& operator=(ScopedTimer&&) = default; void cancel() { - m_cancel = true; + m_maybeTimer.reset(); } - private: - Timer* m_pTimer; - char m_timerMem[sizeof(Timer)]; - bool m_cancel; -}; - -// A timer that provides a similar API to QTimer but uses render events from the -// VSyncThread as its source of timing events. This means the timer cannot fire -// at a rate faster than the user's configured waveform FPS. -class GuiTickTimer : public QObject { - Q_OBJECT - public: - GuiTickTimer(QObject* pParent); - - void start(mixxx::Duration interval); - bool isActive() const { return m_bActive; } - void stop(); - - signals: - void timeout(); - - private slots: - void slotGuiTick(double v); private: - parented_ptr m_pGuiTick; - mixxx::Duration m_interval; - mixxx::Duration m_lastUpdate; - bool m_bActive; + // use std::optional to avoid heap allocation which is frequent + // because of ScopedTimer's temporary nature + std::optional m_maybeTimer; }; diff --git a/src/vinylcontrol/vinylcontrolprocessor.cpp b/src/vinylcontrol/vinylcontrolprocessor.cpp index 8da151938b2d..3e8cfc9474a4 100644 --- a/src/vinylcontrol/vinylcontrolprocessor.cpp +++ b/src/vinylcontrol/vinylcontrolprocessor.cpp @@ -205,7 +205,7 @@ bool VinylControlProcessor::deckConfigured(int index) const { void VinylControlProcessor::receiveBuffer(const AudioInput& input, const CSAMPLE* pBuffer, unsigned int nFrames) { - ScopedTimer t("VinylControlProcessor::receiveBuffer"); + ScopedTimer t(u"VinylControlProcessor::receiveBuffer"); if (input.getType() != AudioInput::VINYLCONTROL) { qDebug() << "WARNING: AudioInput type is not VINYLCONTROL. Ignoring incoming buffer."; return; diff --git a/src/vinylcontrol/vinylcontrolxwax.cpp b/src/vinylcontrol/vinylcontrolxwax.cpp index 80dea92cd0e7..19574a6dff9c 100644 --- a/src/vinylcontrol/vinylcontrolxwax.cpp +++ b/src/vinylcontrol/vinylcontrolxwax.cpp @@ -199,7 +199,7 @@ bool VinylControlXwax::writeQualityReport(VinylSignalQualityReport* pReport) { void VinylControlXwax::analyzeSamples(CSAMPLE* pSamples, size_t nFrames) { - ScopedTimer t("VinylControlXwax::analyzeSamples"); + ScopedTimer t(u"VinylControlXwax::analyzeSamples"); auto gain = static_cast(m_pVinylControlInputGain->get()); // We only support amplifying with the VC pre-amp. diff --git a/src/waveform/renderers/waveformrendererendoftrack.cpp b/src/waveform/renderers/waveformrendererendoftrack.cpp index edef583da39a..414c7e024968 100644 --- a/src/waveform/renderers/waveformrendererendoftrack.cpp +++ b/src/waveform/renderers/waveformrendererendoftrack.cpp @@ -63,7 +63,7 @@ void WaveformRendererEndOfTrack::draw(QPainter* painter, return; } - //ScopedTimer t("WaveformRendererEndOfTrack::draw"); + // ScopedTimer t(u"WaveformRendererEndOfTrack::draw"); const int elapsed = m_timer.elapsed().toIntegerMillis() % kBlinkingPeriodMillis; diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 4837354ee951..b98e57daf228 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -703,7 +703,7 @@ void WaveformWidgetFactory::notifyZoomChange(WWaveformViewer* viewer) { } void WaveformWidgetFactory::render() { - ScopedTimer t("WaveformWidgetFactory::render() %1waveforms", + ScopedTimer t(u"WaveformWidgetFactory::render() %1waveforms", static_cast(m_waveformWidgetHolders.size())); //int paintersSetupTime0 = 0; @@ -778,7 +778,7 @@ void WaveformWidgetFactory::render() { } void WaveformWidgetFactory::swap() { - ScopedTimer t("WaveformWidgetFactory::swap() %1waveforms", + ScopedTimer t(u"WaveformWidgetFactory::swap() %1waveforms", static_cast(m_waveformWidgetHolders.size())); // Do this in an extra slot to be sure to hit the desired interval diff --git a/src/widget/woverview.cpp b/src/widget/woverview.cpp index e49c7a50fe7f..9445922cc0a8 100644 --- a/src/widget/woverview.cpp +++ b/src/widget/woverview.cpp @@ -628,7 +628,7 @@ void WOverview::leaveEvent(QEvent* pEvent) { void WOverview::paintEvent(QPaintEvent* pEvent) { Q_UNUSED(pEvent); - ScopedTimer t("WOverview::paintEvent"); + ScopedTimer t(u"WOverview::paintEvent"); QPainter painter(this); painter.fillRect(rect(), m_backgroundColor); diff --git a/src/widget/woverviewhsv.cpp b/src/widget/woverviewhsv.cpp index e2effb34da81..8f20884b1d2e 100644 --- a/src/widget/woverviewhsv.cpp +++ b/src/widget/woverviewhsv.cpp @@ -18,7 +18,7 @@ WOverviewHSV::WOverviewHSV( } bool WOverviewHSV::drawNextPixmapPart() { - ScopedTimer t("WOverviewHSV::drawNextPixmapPart"); + ScopedTimer t(u"WOverviewHSV::drawNextPixmapPart"); //qDebug() << "WOverview::drawNextPixmapPart()"; diff --git a/src/widget/woverviewlmh.cpp b/src/widget/woverviewlmh.cpp index df43cd9469b6..72ad03124a54 100644 --- a/src/widget/woverviewlmh.cpp +++ b/src/widget/woverviewlmh.cpp @@ -18,7 +18,7 @@ WOverviewLMH::WOverviewLMH( } bool WOverviewLMH::drawNextPixmapPart() { - ScopedTimer t("WOverviewLMH::drawNextPixmapPart"); + ScopedTimer t(u"WOverviewLMH::drawNextPixmapPart"); //qDebug() << "WOverview::drawNextPixmapPart()"; diff --git a/src/widget/woverviewrgb.cpp b/src/widget/woverviewrgb.cpp index acd956aa3bc3..5cc8ced168e6 100644 --- a/src/widget/woverviewrgb.cpp +++ b/src/widget/woverviewrgb.cpp @@ -17,7 +17,7 @@ WOverviewRGB::WOverviewRGB( } bool WOverviewRGB::drawNextPixmapPart() { - ScopedTimer t("WOverviewRGB::drawNextPixmapPart"); + ScopedTimer t(u"WOverviewRGB::drawNextPixmapPart"); //qDebug() << "WOverview::drawNextPixmapPart()"; diff --git a/src/widget/wvumeterbase.cpp b/src/widget/wvumeterbase.cpp index cc9048719a33..08bc7e10e9a7 100644 --- a/src/widget/wvumeterbase.cpp +++ b/src/widget/wvumeterbase.cpp @@ -171,7 +171,7 @@ void WVuMeterBase::render(VSyncThread* vSyncThread) { return; } - ScopedTimer t("WVuMeterBase::render"); + ScopedTimer t(u"WVuMeterBase::render"); updateState(vSyncThread->sinceLastSwap()); diff --git a/src/widget/wvumeterlegacy.cpp b/src/widget/wvumeterlegacy.cpp index a530d3e9e31e..cd490690e4fe 100644 --- a/src/widget/wvumeterlegacy.cpp +++ b/src/widget/wvumeterlegacy.cpp @@ -164,7 +164,7 @@ void WVuMeterLegacy::showEvent(QShowEvent* e) { } void WVuMeterLegacy::paintEvent(QPaintEvent* /*unused*/) { - ScopedTimer t("WVuMeterLegacy::paintEvent"); + ScopedTimer t(u"WVuMeterLegacy::paintEvent"); QPainter p(this);