[Accessibility] Re: [Accessibility-atspi] D-Bus AT-SPI - The way forward

Havoc Pennington hp at redhat.com
Wed Dec 12 13:08:09 PST 2007


Hi,

Rob Taylor wrote:
> CC'ing the D-Bus mailing list as there's lots of interesting stuff here.

OK, this is about 400 topics in one email, cross-posted to 5 mailing 
lists ;-)

I do think the dbus list could be really helpful on a lot of this, and 
that in general people extending or having trouble with dbus have been 
much too slow to mail the list.

Can I propose that if people are seriously working on, or seriously 
having a problem with, any of these issues that they post a single-topic 
thread to the dbus list per-issue.

The vast majority of these issues have been discussed before, and there 
is frequently even a "plan of record" and we just lack someone 
implementing it. A few of these issues are already solved, even, and 
simply asking might save someone some trouble.

I'll comment in a random way on a few of the points in here below, but I 
dread a thread with many topics on 5 different lists, so can I ask that 
further followup be single-topic, change the subject line, and drop the 
non-dbus lists? (assuming the followup is about dbus generally and not a11y)


OK, some quick comments on specific points.

Performance
===

D-Bus performance is already well-known and pretty well understood; I 
got the same results as the AtSpiDbusInvestigation page in 2004:
http://lists.freedesktop.org/pipermail/dbus/2004-November/001779.html
and updated information and suggestions related to this here:
http://lists.freedesktop.org/archives/dbus/2007-October/008822.html

The basic fact is that for a round-trip blocking method call there is a 
constant-factor overhead of around 3x vs. raw sockets. (ORBit is not a 
lot slower than raw sockets, iirc.) If you use the bus daemon, this 
inherently doubles, since there are double the number of "hops." Looking 
at the causes of this overhead, it is difficult to change fundamentally; 
I'm sure with effort you could get it down to 2x, and perhaps a bit 
better by writing a libdbus replacement with less flexibility. But you 
won't get to 1x.

The constant factor falls out of a number of design decisions, some of 
them in the protocol, and others in libdbus. This was intentional. My 
opinion is that these decisions were largely correct, but opinions vary.
(Some of the design decisions are easy to explore changing, such as 
whether to validate the data; see the archive links above.)

Given that fact, I don't think there is much more to say. There is no 
way application design should vary based on whether 2x or 3x was 
measured. Unless you intend to hack on libdbus itself and want to drill 
down into hotspots to fix them, what you as an app developer should have 
in your mind is "there's a single-digit constant-factor overhead vs. raw 
sockets" and "avoid round trips!!!!"

For AT-SPI I bet the bottom line is that you guys have got to reduce the 
amount of traffic and round trips, probably by changing or extending the 
API.

If you need something raw-socket-like, then stick to CORBA, or use D-Bus 
for discovery only then set up a custom socket channel, or whatever. 
There is no reason to drop CORBA when it is suitable. The reason for 
dbus is that (in my opinion) CORBA was not suitable for many desktop 
use-cases. That does not mean CORBA is not suitable for AT-SPI.

Richer Introspection Data
===

Re: struct names in the introspection, etc. I feel sure there are old 
threads on this but am too lazy to dig them up.

Other than digging those up and posting the archive links, I guess the 
first step would be to write up the motivation and proposal on the list. 
  In general it seems like a reasonable idea.

Interface Repository
===

We have certainly discussed on the list simply installing XML files so 
static languages can access them at compile time. Not sure of the status 
of this, but it should amount to a spec patch, maybe even we already 
have a patch. There are definitely old threads and it's worth doing.

A runtime IR service, I'm not sure what it would be for. The dbus 
approach is that each app provides its own introspection data.

This has pros and cons vs. keeping a global repository of types, but I'm 
skeptical that doing it *both* the central IR way and the introspection 
way at the same time makes sense.

IDL vs. XML
===

Remember that writing the XML files by hand is not intended. It would 
not be needed if we had reasonable tools.

The original vision, which I still think would be best, is that you 
implement the object in some language. The XML is then generated by 
scanning that language - pulling docs from the language's native inline 
docs, pulling interfaces from the language's native interfaces, etc. 
This extracted XML can then be installed for use by static languages, 
for example. Definitely this is how the GLib bindings were intended to 
work; we did NOT want people to have to write an XML file then generate 
code from it. (For the "server side" or object implementation, that is.)

A CORBA-like IDL fits into this same concept. The idea is that if you 
wanted to hand-write your IDL, maybe a nice CORBA-style syntax would be 
preferred. No problem. You use libIDL to write a little tool to convert 
your nice syntax to the XML format.

In other words, the XML format is a lingua franca. That's part of why 
XML is used, because you can write quick tools and scripts in Python or 
Perl or whatever that manipulate the XML.


Passing Types With Objects/Structs
===

The major point here that I agree with: as Michael says, the 
introspection calls probably add up to a lot of round trips, especially 
for dynamic languages.

However, there are surely some good ways to optimize that which are 
backward compatible and *simple* - i.e. that do not imply that dbus has 
a global-across-all-processes type system or type repository, because it 
doesn't and imo shouldn't.

<background digression>
A principle of the dbus design is that dbus is NOT a type system, it's a 
marshaling system.

That was part of the whole point of dbus vs. CORBA: you are supposed to 
use the type system *of your programming language* or *of your component 
system*. dbus is a *marshaling* mechanism, not a universe of types. For 
dbus, "struct A { int }" and "struct B { int }" are the same thing.

Unlike at least some of the old theories about how to use CORBA, dbus is 
NOT intended to be a component system; it is NOT intended to be a way to 
define cross-language objects or types. It *can* be used to *remote* a 
component. See D-Bus FAQ for more on IPC vs. components.

The out-of-band introspection data is intended to provide optional hints 
for how to generate a language binding. But it's also intended that the 
introspection data can be ignored; you can just treat the dbus messages 
as raw structured data.
</background digression>

So, how would I approach the introspection round trips and/or bandwidth? 
I would think some combination of standard strategies, such as batch 
calls to introspect multiple objects at once. Another possible approach 
would be to have an implicit type repository *per application* - 
something like an extended Introspect() call that lets you specify an 
introspection context, and in an introspection context the app would 
send you each interface only once, and refer to it by reference the 
second and subsequent times.

Probably step 1 would be to profile the bottlenecks for the dynamic 
bindings that use introspection, with some common apps they might be 
introspecting. We should not add a bunch of complexity on performance 
speculation, only on performance data.

For the solution, I think it's important to keep the layering that the 
introspection data is an *optional hint* that can be used to interpret 
dbus messages.

Object Paths
===

 > In terms of attaching objects to a connection, it'd be really nice to
 > have the attach method take not only a object path, but also a
 > possible
 > function for parsing the remaining components of a path whose prefix
 > matches the given object path.

If I understand this correctly, this is already allowed. You can 
register a handler for an entire subtree of the object path namespace. 
The intended usage of that is to allow you to do your own path to 
handler mapping, e.g. the example I usually give is that you could 
register to handle "/documents" and then do your own interpretation of 
"/documents/0", "/documents/1", etc.

Object References
===

There has been past discussion, possibly worth digging up, about some 
standard format for a complete "IOR" - which would include a server 
address, optionally a bus name, and an object path. i.e. the info to 
allow you to create a DBusConnection and then create an object proxy.

The "shared connections" feature is intended to support this.

i.e. if you resolved this "IOR" you would have to get the DBusConnection 
from the server address, then create your proxy. Without shared 
connections, you would create a DBusConnection per proxy, which would be 
absurdly, horrifyingly inefficient.

Anyway, I think shared connections are the only hard part about this 
feature, and that part is already implemented.

I think the reason there's no "IOR" feature so far is because very few 
people have needed it. It's rare to want to pass an object reference 
that is "location independent" (not known to be on some specific bus or 
provided by some other specific predefined program). When you're talking 
to another program, and thus getting an object reference, you would 
normally already know what bus that other program is on.

But, if someone thinks this feature through and codes it, it makes 
sense, as I said the shared connections feature is already there and 
intended to support it.

Binary Introspection Data
===

I don't see how this is worth the enormous pain of reimplementing all 
kinds of stuff. It is not even clearly better than XML; there are plenty 
of contexts where XML is more convenient. And there is no proven 
performance problem, or proof that binary would be dramatically better, 
or at least nobody has posted the proof where I've seen it.

I don't see a massive deprecation and reimplementation effort spanning 
quite a few projects, justified purely by subjective aesthetics.

In any case, I bet performance would be better addressed via the 
mechanisms discussed earlier - batching up the introspection data, or 
allowing it to be passed "by reference" when the same app gets the same 
interface a second time. Certainly that seems like the thing to try first.

Perspective
===

Let me say again. I know it's a lot of fun to screw with component 
systems and type systems and IPC systems. (Obviously I've done it 
myself.) However, we should not delude ourselves that this is especially 
*worthwhile* in most cases.

Where are apps having the most trouble, doing the most things wrong, 
etc.? Arcane improvements to the IPC system are not the answer.

Most of the problems are on a higher level. e.g. lack of convenience API 
for stuff like this:
http://svn.mugshot.org/dumbhippo/trunk/client/linux/src/hippo-dbus-helper.h

Or in GNOME, we aren't even using dbus for the baseline, simple 
functionality it already provides; e.g. there's still no single-instance 
support in gtk. Why would we be adding all kinds of new stuff to dbus, 
when we're still sucking at using the functionality we have?

Let's remember that DCOP was implemented in a very short period of time, 
and was dead simple - MUCH less complex than dbus is - and people used 
it heavily and successfully for lots of real functionality.

Havoc


More information about the dbus mailing list