Since KDE dropped CORBA completely, and is using
DCOP everywhere instead, naturally the question arises why aRts
isn't doing so. After all, DCOP support is in
KApplication
, is well-maintained, supposed to
integrate greatly with libICE, and whatever else.
Since there will be (potentially) a lot of people asking whether having MCOP besides DCOP is really necessary, here is the answer. Please don't get me wrong, I am not trying to say “DCOP is bad”. I am just trying to say “DCOP isn't the right solution for aRts” (while it is a nice solution for other things).
First, you need to understand what exactly DCOP was written for. Created in two days during the KDE-TWO meeting, it was intended to be as simple as possible, a really “lightweight” communication protocol. Especially the implementation left away everything that could involve complexity, for instance a full blown concept how data types shall be marshalled.
Even although DCOP doesn't care about certain things (like: how do I send a string in a network-transparent manner?) - this needs to be done. So, everything that DCOP doesn't do, is left to Qt™ in the KDE apps that use DCOP today. This is mostly type management (using the Qt™ serialization operator).
So DCOP is a minimal protocol which perfectly enables KDE applications to send simple messages like “open a window pointing to http://www.kde.org” or “your configuration data has changed”. However, inside aRts the focus lies on other things.
The idea is, that little plugins in aRts will talk involving such data structures as “midi events” and “songposition pointers” and “flow graphs”.
These are complex data types, which must be sent between different objects, and be passed as streams, or parameters. MCOP supplies a type concept, to define complex data types out of simpler ones (similar to structs or arrays in C++). DCOP doesn't care about types at all, so this problem would be left to the programmer - like: writing C++ classes for the types, and make sure they can serialize properly (for instance: support the Qt™ streaming operator).
But that way, they would be inaccessible to everything but direct C++ coding. Specifically, you could not design a scripting language, that would know all types plugins may ever expose, as they are not self describing.
Much the same argument is valid for interfaces as well. DCOP objects don't expose their relationships, inheritance hierarchies, etc. - if you were to write an object browser which shows you “what attributes has this object got”, you'd fail.
While Matthias told me that you have a special function “functions” on each object that tells you about the methods that an object supports, this leaves out things like attributes (properties), streams and inheritance relations.
This seriously breaks applications like aRts-builder. But remember: DCOP was not so much intended to be an object model (as Qt™ already has one with moc and similar), nor to be something like CORBA, but to supply inter-application communication.
Why MCOP even exists is: it should work fine with streams between objects. aRts makes heavily use of small plugins, which interconnect themselves with streams. The CORBA version of aRts had to introduce a very annoying split between “the SynthModule objects”, which were the internal work modules that did do the streaming, and “the CORBA interface”, which was something external.
Much code cared about making interaction between “the SynthModule
objects” and “the CORBA
interface” look natural, but it didn't, because
CORBA knew nothing at all about streams. MCOP
does. Look at the code (something like
simplesoundserver_impl.cc
). Way better! Streams
can be declared in the interface of modules, and implemented in a
natural looking way.
One can't deny it. One of the reasons why I wrote MCOP was speed. Here are some arguments why MCOP will definitely be faster than DCOP (even without giving figures).
An invocation in MCOP will have a six-“long”-header. That is:
magic “MCOP”
message type (invocation)
size of the request in bytes
request ID
target object ID
target method ID
After that, the parameters follow. Note that the demarshalling of this is extremely fast. You can use table lookups to find the object and the method demarshalling function, which means that complexity is O(1) [ it will take the same amount of time, no matter how many objects are alive, or how many functions are there ].
Comparing this to DCOP, you'll see, that there are at least
a string for the target object - something like “myCalculator”
a string like “addNumber(int,int)” to specify the method
several more protocol info added by libICE, and other DCOP specifics I don't know
These are much more painful to demarshall, as you'll need to parse the string, search for the function, etc..
In DCOP, all requests are running through a server (DCOPServer). That means, the process of a synchronous invocation looks like this:
Client process sends invocation.
DCOPserver (man-in-the-middle) receives invocation and looks where it needs to go, and sends it to the “real” server.
Server process receives invocation, performs request and sends result.
DCOPserver (man-in-the-middle) receives result and ... sends it to the client.
Client decodes reply.
In MCOP, the same invocation looks like this:
Client process sends invocation.
Server process receives invocation, performs request and sends result.
Client decodes reply.
Say both were implemented correctly, MCOPs peer-to-peer strategy should be faster by a factor of two, than DCOPs man-in-the-middle strategy. Note however that there were of course reasons to choose the DCOP strategy, which is namely: if you have 20 applications running, and each app is talking to each app, you need 20 connections in DCOP, and 200 with MCOP. However in the multimedia case, this is not supposed to be the usual setting.
I tried to compare MCOP and DCOP, doing an invocation like adding two numbers. I modified testdcop to achieve this. However, the test may not have been precise on the DCOP side. I invoked the method in the same process that did the call for DCOP, and I didn't know how to get rid of one debugging message, so I used output redirection.
The test only used one object and one function, expect DCOPs results to decrease with more objects and functions, while MCOPs results should stay the same. Also, the dcopserver process wasn't connected to other applications, it might be that if many applications are connected, the routing performance decreases.
The result I got was that while DCOP got slightly more than 2000 invocations per second, MCOP got slightly more than 8000 invocations per second. That makes a factor of 4. I know that MCOP isn't tuned to the maximum possible, yet. (Comparison: CORBA, as implemented with mico, does something between 1000 and 1500 invocations per second).
If you want “harder” data, consider writing some small benchmark app for DCOP and send it to me.
CORBA had the nice feature that you could use objects you implemented once, as “separate server process”, or as “library”. You could use the same code to do so, and CORBA would transparently decide what to do. With DCOP, that is not really intended, and as far as I know not really possible.
MCOP on the other hand should support that from the beginning. So you can run an effect inside artsd. But if you are a wave editor, you can choose to run the same effect inside your process space as well.
While DCOP is mostly a way to communicate between apps, MCOP is also a way to communicate inside apps. Especially for multimedia streaming, this is important (as you can run multiple MCOP objects parallely, to solve a multimedia task in your application).
Although MCOP does not currently do so, the possibilities are open to implement quality of service features. Something like “that MIDI event is really really important, compared to this invocation”. Or something like “needs to be there in time”.
On the other hand, stream transfer can be integrated in the MCOP protocol nicely, and combined with QoS stuff. Given that the protocol may be changed, MCOP stream transfer should not really get slower than conventional TCP streaming, but: it will be easier and more consistent to use.
There is no need to base a middleware for multimedia on Qt™. Deciding so, and using all that nice Qt™-streaming and stuff, will easily lead to the middleware becoming a Qt™-only (or rather KDE-only) thing. I mean: as soon as I'll see the GNOMEs using DCOP, too, or something like that, I am certainly proven wrong.
While I do know that DCOP basically doesn't know about the data types
it sends, so that you could use DCOP without using Qt™, look at how
it is used in daily KDE usage: people send types like
QString
, QRect
,
QPixmap
, QCString
, ...,
around. These use Qt™-serialization. So if somebody choose to support
DCOP in a GNOME program, he would either have to claim to use
QString
,... types (although he doesn't do so),
and emulate the way Qt™ does the streaming, or he would send other
string, pixmap and rect types around, and thus not be interoperable.
Well, whatever. aRts was always intended to work with or without KDE, with or without Qt™, with or without X11, and maybe even with or without Linux® (and I have even no problems with people who port it to a popular non-free operating systems).
It is my position that non-GUI-components should be written non-GUI-dependant, to make sharing those among wider amounts of developers (and users) possible.
I see that using two IPC protocols may cause inconveniences. Even more, if they are both non-standard. However, for the reasons given above, switching to DCOP is no option. If there is significant interest to find a way to unite the two, okay, we can try. We could even try to make MCOP speak IIOP, then we'd have a CORBA ORB ;).
I talked with Matthias Ettrich a bit about the future of the two protocols, and we found lots of ways how things could go on. For instance, MCOP could handle the message communication in DCOP, thus bringing the protocols a bit closer together.
So some possible solutions would be:
Write an MCOP - DCOP gateway (which should be possible, and would make interoperation possible) - note: there is an experimental prototype, if you like to work on that.
Integrate everything DCOP users expect into MCOP, and try to only do MCOP - one could add an “man-in-the-middle-option” to MCOP, too ;)
Base DCOP on MCOP instead of libICE, and slowly start integrating things closer together.
However, it may not be the worst possibility to use each protocol for everything it was intended for (there are some big differences in the design goals), and don't try to merge them into one.
Would you like to make a comment or contribute an update to this page?
Send feedback to the KDE Docs Team