From 2da5f905d3173ed97493b11cc682ec379d285895 Mon Sep 17 00:00:00 2001 From: "Ryan P. Bitanga" Date: Wed, 11 Feb 2009 11:16:09 +0000 Subject: [PATCH] Change the queue policy for slow speed runners. They will now wait 400ms before being executed by KRunner svn path=/trunk/KDE/kdelibs/; revision=924670 --- CMakeLists.txt | 1 + private/runnerjobs.cpp | 172 ++++++++++++++++++++++++++++++ private/runnerjobs.h | 125 ++++++++++++++++++++++ runnermanager.cpp | 233 ++++------------------------------------- runnermanager.h | 1 + 5 files changed, 321 insertions(+), 211 deletions(-) create mode 100644 private/runnerjobs.cpp create mode 100644 private/runnerjobs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 15db7e7cc..666fb0995 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,7 @@ set(plasma_LIB_SRCS private/nativetabbar.cpp private/packages.cpp private/paneltoolbox.cpp + private/runnerjobs.cpp private/style.cpp private/toolbox.cpp private/tooltip.cpp diff --git a/private/runnerjobs.cpp b/private/runnerjobs.cpp new file mode 100644 index 000000000..b1bc58b5f --- /dev/null +++ b/private/runnerjobs.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2007, 2009 Ryan P. Bitanga + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "runnermanager.h" + +#include + +//#include + +//#include +#include + +#include "runnerjobs.h" +#include "querymatch.h" + +using ThreadWeaver::Job; +using ThreadWeaver::Weaver; + +namespace Plasma { + +DelayedRunnerPolicy::DelayedRunnerPolicy() + : QueuePolicy() +{} + +DelayedRunnerPolicy::~DelayedRunnerPolicy() +{} + +DelayedRunnerPolicy& DelayedRunnerPolicy::instance() +{ + static DelayedRunnerPolicy policy; + return policy; +} + +bool DelayedRunnerPolicy::canRun(Job *job) +{ + FindMatchesJob *aJob = static_cast(job); + if (QTimer *t = aJob->delayTimer()) { + // If the timer is active, the required delay has not been reached + return !t->isActive(); + } + + return true; +} + +void DelayedRunnerPolicy::free(Job *job) +{ + Q_UNUSED(job) +} + +void DelayedRunnerPolicy::release(Job *job) +{ + free(job); +} + +void DelayedRunnerPolicy::destructed(Job *job) +{ + Q_UNUSED(job) +} + +DefaultRunnerPolicy::DefaultRunnerPolicy() + : QueuePolicy(), + m_cap(2) +{} + +DefaultRunnerPolicy::~DefaultRunnerPolicy() +{} + +DefaultRunnerPolicy& DefaultRunnerPolicy::instance() +{ + static DefaultRunnerPolicy policy; + return policy; +} + +bool DefaultRunnerPolicy::canRun(Job *job) +{ + Plasma::AbstractRunner *runner = static_cast(job)->runner(); + QMutexLocker l(&m_mutex); + + if (m_runCounts[runner->name()] > m_cap) { + return false; + } else { + ++m_runCounts[runner->name()]; + return true; + } +} + +void DefaultRunnerPolicy::free(Job *job) +{ + Plasma::AbstractRunner *runner = static_cast(job)->runner(); + QMutexLocker l(&m_mutex); + + --m_runCounts[runner->name()]; +} + +void DefaultRunnerPolicy::release(Job *job) +{ + free(job); +} + +void DefaultRunnerPolicy::destructed(Job *job) +{ + Q_UNUSED(job) +} + +//////////////////// +// Jobs +//////////////////// + +FindMatchesJob::FindMatchesJob(Plasma::AbstractRunner *runner, + Plasma::RunnerContext *context, QObject *parent) + : ThreadWeaver::Job(parent), + m_context(context), + m_runner(runner), + m_timer(0) +{ + if (runner->speed() == Plasma::AbstractRunner::SlowSpeed) { + assignQueuePolicy(&DelayedRunnerPolicy::instance()); + } else { + assignQueuePolicy(&DefaultRunnerPolicy::instance()); + } +} + +FindMatchesJob::~FindMatchesJob() +{ +} + +QTimer* FindMatchesJob::delayTimer() const +{ + return m_timer; +} + +void FindMatchesJob::setDelayTimer(QTimer *timer) +{ + m_timer = timer; +} + +void FindMatchesJob::run() +{ +// kDebug() << "Running match for " << m_runner->objectName() +// << " in Thread " << thread()->id() << endl; + m_runner->performMatch(*m_context); +} + +int FindMatchesJob::priority() const +{ + return m_runner->priority(); +} + +Plasma::AbstractRunner* FindMatchesJob::runner() const +{ + return m_runner; +} + +} // Plasma namespace + +// #include "runnerjobs.moc" diff --git a/private/runnerjobs.h b/private/runnerjobs.h new file mode 100644 index 000000000..e6258ac48 --- /dev/null +++ b/private/runnerjobs.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007, 2009 Ryan P. Bitanga + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_RUNNERJOBS_H +#define PLASMA_RUNNERJOBS_H + +#include +#include + +#include +#include + +using ThreadWeaver::Job; + +class QTimer; + +namespace Plasma { +// Queue policies + +// QueuePolicy that only allows a job to be executed after +// waiting in the queue for the specified timeout +class DelayedRunnerPolicy : public ThreadWeaver::QueuePolicy +{ +public: + ~DelayedRunnerPolicy(); + + static DelayedRunnerPolicy &instance(); + + bool canRun(Job *job); + void free(Job *job); + void release(Job *job); + void destructed(Job *job); +private: + DelayedRunnerPolicy(); + QMutex m_mutex; +}; + +// QueuePolicy that limits the instances of a particular runner +class DefaultRunnerPolicy : public ThreadWeaver::QueuePolicy +{ +public: + ~DefaultRunnerPolicy(); + + static DefaultRunnerPolicy &instance(); + + void setCap(int cap) + { + m_cap = cap; + } + int cap() const + { + return m_cap; + } + + bool canRun(Job *job); + void free(Job *job); + void release(Job *job); + void destructed(Job *job); +private: + DefaultRunnerPolicy(); + + int m_cap; + QHash m_runCounts; + QMutex m_mutex; +}; + +/* ThreadWeaver work around: + * There is no method exposed that allows us to inform + * ThreadWeaver that a previously unavailable job is now + * available; thus, we use an empty job to wake up the threads + */ +class DummyJob : public ThreadWeaver::Job +{ + public: + DummyJob(QObject *parent) : Job(parent) {} + ~DummyJob() {} + private: + void run() {} +}; + +/* + * FindMatchesJob class + * Class to run queries in different threads + */ +class FindMatchesJob : public Job +{ +public: + FindMatchesJob(Plasma::AbstractRunner *runner, + Plasma::RunnerContext *context, QObject *parent = 0); + ~FindMatchesJob(); + + int priority() const; + Plasma::AbstractRunner* runner() const; + + QTimer* delayTimer() const; + void setDelayTimer(QTimer *timer); + +protected: + void run(); + +private: + Plasma::RunnerContext *m_context; + Plasma::AbstractRunner *m_runner; + QTimer *m_timer; +}; + +} + +#endif diff --git a/runnermanager.cpp b/runnermanager.cpp index bb034a377..b7b18bbd5 100644 --- a/runnermanager.cpp +++ b/runnermanager.cpp @@ -35,10 +35,9 @@ #include #include -#include -#include #include +#include "private/runnerjobs.h" #include "querymatch.h" using ThreadWeaver::Weaver; @@ -47,213 +46,6 @@ using ThreadWeaver::Job; namespace Plasma { -/***************************************************** -* RunnerRestrictionPolicy class -* Restricts simultaneous jobs of the same type -* Similar to ResourceRestrictionPolicy but check the object type first -******************************************************/ -class RunnerRestrictionPolicy : public ThreadWeaver::QueuePolicy -{ -public: - ~RunnerRestrictionPolicy(); - - static RunnerRestrictionPolicy &instance(); - - void setCap(int cap) - { - m_cap = cap; - } - int cap() const - { - return m_cap; - } - - bool canRun(Job *job); - void free(Job *job); - void release(Job *job); - void destructed(Job *job); -private: - RunnerRestrictionPolicy(); - - int m_count; - int m_cap; - QMutex m_mutex; -}; - -RunnerRestrictionPolicy::RunnerRestrictionPolicy() - : QueuePolicy(), - m_count(0), - m_cap(2) -{ -} - -RunnerRestrictionPolicy::~RunnerRestrictionPolicy() -{ -} - -RunnerRestrictionPolicy& RunnerRestrictionPolicy::instance() -{ - static RunnerRestrictionPolicy policy; - return policy; -} - -bool RunnerRestrictionPolicy::canRun(Job *job) -{ - Q_UNUSED(job) - QMutexLocker l(&m_mutex); - if (m_count > m_cap) { - return false; - } else { - ++m_count; - return true; - } -} - -void RunnerRestrictionPolicy::free(Job *job) -{ - Q_UNUSED(job) - QMutexLocker l(&m_mutex); - --m_count; -} - -void RunnerRestrictionPolicy::release(Job *job) -{ - free(job); -} - -void RunnerRestrictionPolicy::destructed(Job *job) -{ - Q_UNUSED(job) -} - -// QueuePolicy that limits the instances of a particular runner -class DefaultRunnerPolicy : public ThreadWeaver::QueuePolicy -{ -public: - ~DefaultRunnerPolicy(); - - static DefaultRunnerPolicy &instance(); - - void setCap(int cap) - { - m_cap = cap; - } - int cap() const - { - return m_cap; - } - - bool canRun(Job *job); - void free(Job *job); - void release(Job *job); - void destructed(Job *job); -private: - DefaultRunnerPolicy(); - - int m_cap; - QHash m_runCounts; - QMutex m_mutex; -}; - -/***************************************************** -* FindMatchesJob class -* Class to run queries in different threads -******************************************************/ -class FindMatchesJob : public Job -{ -public: - FindMatchesJob(Plasma::AbstractRunner *runner, - Plasma::RunnerContext *context, QObject *parent = 0); - - int priority() const; - Plasma::AbstractRunner* runner() const; - -protected: - void run(); -private: - Plasma::RunnerContext *m_context; - Plasma::AbstractRunner *m_runner; -}; - -FindMatchesJob::FindMatchesJob(Plasma::AbstractRunner *runner, - Plasma::RunnerContext *context, QObject *parent) - : ThreadWeaver::Job(parent), - m_context(context), - m_runner(runner) -{ - if (runner->speed() == Plasma::AbstractRunner::SlowSpeed) { - assignQueuePolicy(&RunnerRestrictionPolicy::instance()); - } else { - assignQueuePolicy(&DefaultRunnerPolicy::instance()); - } -} - -void FindMatchesJob::run() -{ -// kDebug() << "Running match for " << m_runner->objectName() -// << " in Thread " << thread()->id() << endl; - m_runner->performMatch(*m_context); -} - -int FindMatchesJob::priority() const -{ - return m_runner->priority(); -} - -Plasma::AbstractRunner* FindMatchesJob::runner() const -{ - return m_runner; -} - -DefaultRunnerPolicy::DefaultRunnerPolicy() - : QueuePolicy(), - m_cap(2) -{ -} - -DefaultRunnerPolicy::~DefaultRunnerPolicy() -{ -} - -DefaultRunnerPolicy& DefaultRunnerPolicy::instance() -{ - static DefaultRunnerPolicy policy; - return policy; -} - -bool DefaultRunnerPolicy::canRun(Job *job) -{ - QMutexLocker l(&m_mutex); - - Plasma::AbstractRunner *runner = static_cast(job)->runner(); - - if (m_runCounts[runner->name()] > m_cap) { - return false; - } else { - ++m_runCounts[runner->name()]; - return true; - } -} - -void DefaultRunnerPolicy::free(Job *job) -{ - QMutexLocker l(&m_mutex); - - Plasma::AbstractRunner *runner = static_cast(job)->runner(); - - --m_runCounts[runner->name()]; -} - -void DefaultRunnerPolicy::release(Job *job) -{ - free(job); -} - -void DefaultRunnerPolicy::destructed(Job *job) -{ - Q_UNUSED(job) -} - /***************************************************** * RunnerManager::Private class * @@ -267,8 +59,11 @@ public: deferredRun(0) { matchChangeTimer.setSingleShot(true); + delayTimer.setSingleShot(true); + QObject::connect(&matchChangeTimer, SIGNAL(timeout()), q, SLOT(matchesChanged())); QObject::connect(&context, SIGNAL(matchesChanged()), q, SLOT(scheduleMatchesChanged())); + QObject::connect(&delayTimer, SIGNAL(timeout()), q, SLOT(unblockJobs())); } void scheduleMatchesChanged() @@ -297,7 +92,6 @@ public: // to half the number of threads const int cap = qMax(2, numThreads/2); DefaultRunnerPolicy::instance().setCap(cap); - RunnerRestrictionPolicy::instance().setCap(cap); //If set, this list defines which runners won't be used at runtime //blacklist = config.readEntry("blacklist", QStringList()); @@ -376,13 +170,25 @@ public: delete runJob; } + void unblockJobs() + { + // WORKAROUND: Queue an empty job to force ThreadWeaver to awaken threads + // kDebug() << "- Unblocking jobs -" << endl; + DummyJob *dummy = new DummyJob(q); + Weaver::instance()->enqueue(dummy); + QObject::connect(dummy, SIGNAL(done(ThreadWeaver::Job*)), dummy, SLOT(deleteLater())); + } + + // Delay in ms before slow runners are allowed to run + static const int slowRunDelay = 400; + RunnerManager *q; QueryMatch deferredRun; RunnerContext context; QTimer matchChangeTimer; + QTimer delayTimer; // Timer to control when to run slow runners QHash runners; QList searchJobs; -// QStringList prioritylist; bool loadAll; KConfigGroup config; }; @@ -523,10 +329,15 @@ void RunnerManager::launchQuery(const QString &term, const QString &runnerName) // kDebug() << "launching" << r->name(); FindMatchesJob *job = new FindMatchesJob(r, &d->context, this); connect(job, SIGNAL(done(ThreadWeaver::Job*)), this, SLOT(jobDone(ThreadWeaver::Job*))); + if (r->speed() == AbstractRunner::SlowSpeed) { + job->setDelayTimer(&d->delayTimer); + } Weaver::instance()->enqueue(job); d->searchJobs.append(job); } } + // Start timer to unblock slow runners + d->delayTimer.start(RunnerManagerPrivate::slowRunDelay); } bool RunnerManager::execQuery(const QString &term) diff --git a/runnermanager.h b/runnermanager.h index 9a8a2d54f..1a7ba4b13 100644 --- a/runnermanager.h +++ b/runnermanager.h @@ -146,6 +146,7 @@ class PLASMA_EXPORT RunnerManager : public QObject Q_PRIVATE_SLOT(d, void scheduleMatchesChanged()) Q_PRIVATE_SLOT(d, void matchesChanged()) Q_PRIVATE_SLOT(d, void jobDone(ThreadWeaver::Job*)) + Q_PRIVATE_SLOT(d, void unblockJobs()) RunnerManagerPrivate * const d;