[Panel-devel] Proposal for changes to KRunner

Ryan Bitanga ephebiphobic at gmail.com
Tue Nov 20 17:00:51 CET 2007


On Nov 19, 2007 12:14 AM, Aaron J. Seigo <aseigo at kde.org> wrote:
> this is a bit of a literal, and perhaps not entirely accurate, interpretation
> of the class name. it's SearchAction because it represents an action to be
> taken if the user selects that match. it really has nothing to do with
> noun/verb, and indeed some of SearchActions returned by runners are certainly
> action sounding "phrases".

My point was each match, as it is in its current form, represents a
single action that can be performed. One action that I want to be
implemented is "Set as Default". Now if a SearchAction is labeled "Set
as Default" is given, it is unclear what will be set as the default
action. Do we set the "Set as Default" action as the default? Now of
course, we can add an addVerb() method to SearchAction and somehow let
the GUI let the user choose between several possible actions. My point
is it makes more sense for a SearchAction to represent a match which
we can perform _actions_ to instead of the action that the person
wants to perform. Of course, it's totally possible to do this with
SearchAction, except I thought a name like SearchMatch would be a
slightly more fitting name. IMHO it makes more sense to associate
multiple actions with a SearchMatch class than with a SearchAction
class. So I suppose it's only a matter of difference in taste.
> have you done any benchmarking on how fast/slow QAction creation is? of
> course, fetchActions would have to create the actions so we're left with
> creating two objects (including the QAction) instead of just one. so this
> would, if fetchActions is used, actually be slower and more memory intensive
> than simply creating QActions in the first place.
>

Which was why I later pointed out that we didn't really need
SearchAction to inherit from QAction and be a QObject. If all we're
looking for is something to contain, text, icon and data fields, we
don't need a full blown QAction subclass. Meta-objects carry extra
baggage with them.

> i'm not sure i understand exactly what you're trying to achieve here, but if
> i'm getting it right: you're looking for a second-pass run, where runners can
> process the matches of other runners? filter runners or action-augmenting
> runners?
>
The intention was for a given match with multiple actions that can be
performed on it, the runner should be able to distinguish which
actions to perform. So yes, filtering will occur, but runners will
only be concerned with matches they provided. So no external filtering
runners would be necessary because the runner would select between
possible actions for a given match itself.

> > This would also allow us to permit user-created actions
> > and have KRunner scan a directory and then add user-created actions to
> > the pool of possible actions for that runner via an addAction(const
> > QString& icon, const QString& name, const QString& exec, const
> > QString& mimetype = QString::null) method. This would mimic behavior
> > for creating konqueror service menus. We could write a dialog box for
> > the creation of user-created actions to make it easier for users.
>
> so making SearchAction more expressive would probably be a good first step.
any ideas how to go about this?

> the benefit of subclassing qaction is being able to use it in a number
> flexible ways, including direct invocation via triggered() and by putting it
> into widgets that accept QActions (which is all of them).
>
> it also gives us an API that any Qt developer would be familiar with.
so why not provide a similar API by reimplementing the functions that
are useful to runner authors?

>
> what exactly is the benefit of not using QAction?
>
This comes at the expense of thread-safety. Using ThreadWeaver,
threads don't last the entirety of program execution. Observing
debugger output will show you that threads are created and terminated
on demand. From what I observed, this comes with the drawback of the
event loops of the threads being short-lived if they are started at
all. I could of course be wrong because I didn't really dig deep once
my initial attempt to multithread KRunner didn't work with QAction
based SearchActions. However, logically, if threads exit before the
program is done, objects created in the context of that thread are
destroyed as well. QObjects are associated with threads and expect to
receive events from the event loop of the associated thread. We can of
course allocate objects on the heap then change the thread affinity of
the QObjects, but they would be executed in the context of the GUI
thread. By doing so, we get a bunch of asynchronous calls instead of
true parallel execution and thereby erase all gains obtained through
multithreading. Again, I could be wrong on this, but this is how I
understood it to be.

We don't actually _have_ to use ThreadWeaver to implement
multithreading. Another option would be to subclass AbstractRunner
from QThread, but I think ThreadWeaver is a better option because 1)
we control the number of threads and 2) using ThreadWeaver insulates
runner authors from learning the QThread API. My patch allowed
multithreading while not requiring changes to AbstractRunner because
the multithreading was accomplished in KRunner, specifically in
interface.cpp and SearchContext was simply made thread-safe. With
respect to controlling the number threads, I observed that not all
threads will execute in parallel. For one of my classes, my professor
asked us to execute a function in multiple threads. Limited by
creating and executing threads in the main thread, I found that a
maximum of three threads, instead of the possible nine, were running
concurrently because the code to be executed in the thread was simple.
So in the context of KRunner, having a thread for each runner isn't
always desirable because more often than not some threads will execute
faster than the others and it would be more efficient to reuse those
threads instead of simply suspending them. As stated in the
ThreadWeaver apidox, more threads require more memory; besides,
functions aren't always guaranteed to be executed in parallel anyway.
However, we need the option of controlling the number of threads
because CPU's will gain additional cores per year and the best way (if
not the only way) to take advantage of the additional power produced
by parallel processors is multithreading. Controlling the number of
threads will enable us to scale better with multiple cores in the CPU.

If you're still not sold on multithreading, the advantage is higher
utilization of the CPU. CPU's spend most of their time in the idle
state (run powertop to see just how often your CPU is idle). This can
be caused by many things but one of the reasons is waiting for memory.
Having multiple threads of execution allows parallel processing in
that while one thread is blocked, another thread is executed and the
CPU spends less time idle. This of course is the concept behind the
Sun Niagara family of processors (UltraSPARC T1 and T2) with the T1
executing 32 threads at a time, IIRC. I think Intel's Nehalem
scheduled for next year will allow execution of 16 threads. I digress.
My point is parallel execution is pretty much the future because chip
makers will continue to produce CPU's with an increasing number of
cores which single-threaded applications will not be able to make much
use of. So by multithreading KRunner we are really future-proofing it.

> exact and possible have almost nothing to do with the default match. if a
> runner determines that "konsole" is an "exact match" for "kon" then it can
> say so.

Yes i am aware of that. But the selection of the default match is
based on the first exact match retrieved, or if there are no exact
matches, the first possible match, am I not right? So flexibility is
lost there, because exact matches are set as default before any
possible matches. But this isn't difficult to fix.

>
> i have been considering moving the default action selection out of krunner
> itself and into SearchContext
I guess this would be an acceptable move. At the very least it would
simplify krunner.

>
> runners already have no clue what the default match is =)
Agreed but users can't set the default match as of the moment. krunner
picks one for them.

> this could, of course, be done with the current design.
I know and I'm working on it for ServiceRunner for eventual
integration with Raptor. Siraj, if you're reading this, I'll work on
the usage database for Raptor :) Well I did implement part of it
already so I might as well finish it, right?

No comment on the "direct object" idea? I'll see if I can put
something within the next few hours so you can have an idea of what
I've been talking about.

Cheers,
Ryan


More information about the Panel-devel mailing list