/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef INCLUDED_VCL_TASK_STOPWATCH_HXX #define INCLUDED_VCL_TASK_STOPWATCH_HXX #include #include #include #include /** * Helper class primary used to track time of long running iterating tasks. * * Normally it should be sufficient to instantiate the watch object before * starting the iteration and query continueIter() at the end of each. * * Called Stopwatch, because there is already a Timer class in the Scheduler. * * TODO: merge into the general Scheduler, so this can also be used to track * Task runtimes in a more general way. * TODO: handle fast iterations, where continueIter is called multiple times * per tick, by counting the iterations per tick and use that for approximation. **/ class VCL_DLLPUBLIC TaskStopwatch { static constexpr VclInputFlags eDefaultInputStop = VCL_INPUT_ANY & ~VclInputFlags::TIMER; static constexpr unsigned int nDefaultTimeSlice = 50; static unsigned int m_nTimeSlice; sal_uInt64 m_nStartTicks; sal_uInt64 m_nIterStartTicks; bool m_bConsiderLastIterTime; VclInputFlags m_eInputStop; bool nextIter() { sal_uInt64 nCurTicks = tools::Time::GetSystemTicks(); // handle system ticks wrap as exceeded time slice if (nCurTicks < m_nStartTicks) return false; if (m_bConsiderLastIterTime) { // based on the last iter runtime, we don't expect to finish in time // m_nTimeSlice < (nCurTicks - m_nStartTicks) + (nCurTicks - m_nIterStartTicks) if (m_nTimeSlice < 2 * nCurTicks - m_nIterStartTicks - m_nStartTicks) return false; } // time slice exceeded else if (m_nTimeSlice < nCurTicks - m_nStartTicks) return false; m_nIterStartTicks = nCurTicks; return !Application::AnyInput(m_eInputStop); } public: /** * Per default the watch considers the last iter time when asking for an * other iteration, so considers Scheduler::acceptableTaskTime as a * maximum value. * * If you already know your iter time vary in a large range, consider * setting bConciderLastIterTime to false, so Scheduler::acceptableTaskTime * will be used as a minimum time slot. **/ TaskStopwatch(bool bConciderLastIterTime = true) : m_nStartTicks(tools::Time::GetSystemTicks()) , m_nIterStartTicks(m_nStartTicks) , m_bConsiderLastIterTime(bConciderLastIterTime) , m_eInputStop(eDefaultInputStop) { } /** * Returns true, if another iteration will probably pass in the time slot **/ bool continueIter() { return nextIter(); } /** * Reset the stopwatch **/ void reset() { m_nStartTicks = tools::Time::GetSystemTicks(); m_nIterStartTicks = m_nStartTicks; } /** * Sets the input events, which should also "exceed" the stopwatch. * * Per default this ignores the VclInputFlags::TIMER. */ void setInputStop(VclInputFlags eInputStop = eDefaultInputStop) { m_eInputStop = eInputStop; } VclInputFlags inputStop() const { return m_eInputStop; } /** * Sets the time considered the acceptable maximum for a task to run * * This is an orientation for long time background jobs to yield to * the scheduler, so Idle task don't starve each other too much. **/ static unsigned int timeSlice() { return m_nTimeSlice; } static void setTimeSlice(unsigned int nTimeSlice) { m_nTimeSlice = nTimeSlice; } }; #endif // INCLUDED_VCL_TASK_STOPWATCH_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */