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
This commit is contained in:
Ryan P. Bitanga 2009-02-11 11:16:09 +00:00
parent bb01ec253d
commit 2da5f905d3
5 changed files with 321 additions and 211 deletions

View File

@ -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

172
private/runnerjobs.cpp Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2007, 2009 Ryan P. Bitanga <ryan.bitanga@gmail.com>
*
* 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 <QTimer>
//#include <KDebug>
//#include <Weaver/DebuggingAids.h>
#include <Weaver/ThreadWeaver.h>
#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<FindMatchesJob*>(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<FindMatchesJob*>(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<FindMatchesJob*>(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"

125
private/runnerjobs.h Normal file
View File

@ -0,0 +1,125 @@
/*
* Copyright (C) 2007, 2009 Ryan P. Bitanga <ryan.bitanga@gmail.com>
*
* 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 <QHash>
#include <QMutex>
#include <Weaver/Job.h>
#include <Weaver/QueuePolicy.h>
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<QString, int> 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

View File

@ -35,10 +35,9 @@
#include <Weaver/DebuggingAids.h>
#include <Weaver/Thread.h>
#include <Weaver/Job.h>
#include <Weaver/QueuePolicy.h>
#include <Weaver/ThreadWeaver.h>
#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<QString, int> 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<FindMatchesJob*>(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<FindMatchesJob*>(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<QString, AbstractRunner*> runners;
QList<FindMatchesJob*> 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)

View File

@ -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;