[omniORB] Re: [PATCH] "Safe" shortcut calls

Nathaniel Smith njs@uclink4.berkeley.edu
Tue, 7 May 2002 20:18:01 -0700


--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Tue, May 07, 2002 at 08:09:25PM -0700, Nathaniel Smith wrote:
>
> So, attached is a patch to (yesterday's) CVS, plus the original
> message I sent with all the gory implementation details, API details,
> benchmarks, etc.

Gah!  Must... think... before... pressing... send...

_Here_ are the promised attachments.

-- Nathaniel

-- 
Eternity is very long, especially towards the end.
  -- Woody Allen

This email may be read aloud.

--pf9I7BMVVzbSWLtt
Content-Type: text/plain; charset=us-ascii
Content-Description: [PATCH] "Safe" shortcut calls for omniORB 4
Content-Disposition: attachment; filename=blah

Attached is a patch to the current omniORB 4 CVS which adds a new
POA shortcut policy type, LOCAL_CALLS_SHORTCUT_SAFE.  By "safe" we
mean, it's safe to deactivate objects at any time, and shutdown,
forwarding (I think it would even work to do crazy things like
forwarding an object reference from a local POA set to safe shortcut
mode to a local POA set to unsafe shortcut mode), DII, etc. should all
work correctly, even if shortcut calls may be in progress.  I believe
it also correctly handles the case where some code is compiled with
-Wbshortcut and some is not.

Simple testing (making lots of calls to an empty method "void test(){}")
via different mechanisms suggests that this is implementation is
pretty fast -- about 10 times faster than a normal through-poa call
and 3 times slower than the current "unsafe" shortcut mechanism.
(This is on x86 Linux -- on other platforms I'd guess it's about 3
times faster than through-poa calls and 10 times slower than "unsafe"
shortcuts -- more about this later.)  The actual numbers my program
spits out are:

Non-virtual is: 2.11988 cycles/op
Virtual is: 18.054 cycles/op
Non-shortcut is: 1618.97 cycles/op  (1296.63 without POA::Current)
Shortcut is: 39.2757 cycles/op
Safe shortcut is: 156.395 cycles/op
(The last number becomes 465.215 when using the mutex implementation of
omniAtomicInt.)

(this is using the Intel rdtsc counter to count processor cycles, and
is fine enough to vary by +-20 depending on things like stack
alignment -- that should give some idea of the margin of error.)

For a more real-world test, I've successfully run Berlin with my
changes.  Everything seems to work fine (there are some bugs in
Berlin that make it harder to tell if everything's working correctly,
but they seem to be the same bugs that we see without any shortcut
optimizations), and the speed-up is quite noticeable.  In particular,
for a simple test of redraw speed under different conditions, I find:
  LOCAL_CALLS_THROUGH_POA:    68ms
    without POA::Current:     64ms
  LOCAL_CALLS_SHORTCUT:       36ms
  LOCAL_CALLS_SHORTCUT_SAFE:  38ms

As you might imagine, I've been hoping that we can get these into the
omniORB 4 release in some form -- it would help us working on Berlin
lots.  So, if you have any questions, please ask; if you want a part
rewritten, please ask; if you think something needs cleaning up,
please ask -- I'm sending this to get your comments, and hopefully
(eventual) merging into the main tree.
(I don't really know what your policy on patches is wrt the release --
I would be unsurprised if you wanted to wait until 4.0.1; I would be
unsurprised and pleased if you accepted the patch now.  I am fairly
confident that it's correct, modulo some questions I mention later on,
and quite certain that it won't hurt anyone who doesn't do something
special to turn shortcuts on, modulo a tiny bit of memory, so I don't
think it would actually hurt anything to put it into the 4.0.0 beta.)
The rest of this email tries to give some sort of overview of what's
the patch does, so you can better reply :-).

The API:
   To the user, it all looks just like the current shortcut support,
except that there's now a third policy: LOCAL_CALLS_SHORTCUT_SAFE.
You can have POA's with both types of shortcut calls running in the
same process, etc.
   We continue to use -Wbshortcut to turn on shortcut-capability when
compiling idl files; the cost of supporting both types of shortcut
with the same stub/skeleton code is about 1 processor cycle per call
(one 'if'), so we go for flexibility and simplicity and just support
both.

The inner workings (or, "How come it's so fast?"):
   We create a new type "omni::omniAtomicInt" which is basically just
an integer that supports atomic operations like increment,
decrement_and_test, etc.  The wonderful thing about this is that on
many processors, these operations can be implemented by a bit of
inline asm, and are then orders of magnitudes faster than using a
mutex.  At the moment, include/omniORB4/internal/atomicInt.h only
knows how to do this on x86 Linux, but it would be easy to add to
other platforms.  Making it work on a different Linux port is entirely
trivial, for example -- just check that the routines in <asm/atomic.h>
are safe to use outside of kernel space, and add that platform to an
#if in atomicInt.h.  For other OS's that have compiler support for
inline asm and a rich enough instruction set, one could just steal the
code from <asm/atomic.h> and use that -- very simple.
   Unfortunately, Sparc (which I know you guys like :-)) is one of the
processors that can't support atomic operations.  In this case, the
omniAtomicInt implementation falls back on mutexes, and still gives a
nice speed-up, with exactly the same behaviour (so if you code for
safe shortcuts on one platform, and switch to a different platform,
it'll always work, and you'll always be at a speed advantage as
compared to through-poa calls).
   These atomicInt's are used to reference count shortcut invocations.
The class responsible for making all this work is the
omniShortcutManager.  omniShortcutManager's hold an atomicInt
(initialized to 1), plus other bookkeeping miscellany, and are created
on-demand for each omniObjTableEntry.  When they get activated (ie,
it becomes possible to make shortcut calls via them), then they grab
a reference to their omniObjTableEntry, and increment its
pd_nInvocations count -- these references will sort of "stand in" for
all the shortcut calls made via this manager.  When a call is
dispatched to via the normal mechanisms in a shortcut-enabled POA,
we use code just like the current shortcut implementation's to create
and pass a omniShortcutManager (along with the appropriate
omniServant) to ObjRef's that should use shortcuts for future calls.
The ObjRef's use the omniShortcutManager and omniServant to create and
save a omniShortcutHolder, which is just a struct to hold an
omniShortcutManager and an actual _impl_ object.  (We use this struct
to avoid weird race conditions between people trying to invoke and
people trying to change the shortcut pointer -- you get all sorts of
problems depending on which order you assign the pointers in, etc.
It's also a mild win on memory, I suppose -- all ObjRef's that refer
to the same _impl_ object of the same type share a single
omniShortcutHolder.)
   When a shortcut call comes in to a ObjRef that has a ShortcutHolder
sitting around, it calls omniShortcutManager::enterCall() (which
increments the reference counter), then does the call and saves its
return value, then calls omniShortcutManager::exitCall(), then returns
the return value.
   The omniShortcutManager, then, keeps count of the references, and
when it's time to deactivate an omniObjTableEntry, setDeactivating
calls please_deactivate on its omniShortcutManager, which decrements
the reference count (meaning that it can now hit 0).  If it hits 0
immediately, then deactivate_please simply drops the pseudo-references
it holds, and continues with normal deactivation.  If it doesn't hit 0
immediately, then deactivation continues as if calls were still
outstanding.  When the last invocation then calls exitCall(), it drops
the pseudo-references, and possibly calls lastInvocationHasCompleted.
   The above is actually not quite true -- we also have to deal with
deactivation.  In particular, there could be nasty cases where the
counter hits 0 twice (eg, if it hits 0, then a new call comes in,
bumps it to 1, and then drops it to 0 again), or where an incoming
invocation gets it's reference to an omniShortcutManager, then that
manager is deleted, and then the invocation calls enterCall() (which
would have prevented it being deleted, had it been in time, but it
wasn't).  The trick we use is to have a single static omniAtomicInt
named omni::omniShortcutManager::count_incrementers which ObjRef's
increment before reading their local _shortcut_holder variable, and
then decrement again after they've called enterCall() (with a little
extra jazz thrown in for the mutex case to make sure we only do one
lock/unlock on the way in and on the way out).  When we want to turn
off shortcuts, then (eg, from setDeactivating, or
omniObjRef::_setIdentity), we clear the _shortcut_holder variables and
spin reading count_incrementers until it reads as 0.  (In my tests,
the ORB never had to check it more than once, because invokers hold it
for such a short time -- perhaps 4 asm instructions.  And in the mutex
case, the ORB never has to spin at all, as a side-effect of the mutex
trickery I mentioned.)  Once it's read as 0 once, we know that no-one
else could possibly call enterCall(), and our object can be
deactivated at will.
   That should be enough to let you figure out what's going on :-).

Costs:
   Unless you enable it with -Wbshortcut and setting a shortcut policy
on your POAs, the implementation is very cheap.  Time-wise, it's
equivalent to the current shortcut invocation -- a single extra 'if'
in dispatch(omniLocalIdentity*).  Space-wise, there's an extra 4-8
bytes of static variable for the count_incrementers omniAtomicInt,
plus an extra pointer for each omniObjTableEntry.  This last part is
the bit I'm least sure about -- it's extra overhead for every
activated object, regardless if the user wants to use shortcuts or
not.  On the other hand, that's really not very much -- the patch is
careful not to allocate any memory besides that bit until necessary,
and on my machine that increases the size of an omniObjTableEntry from
88 bytes to 92 -- about 4% increase.  Furthermore, it's per activated
object, not per object reference or something like that, so the
overall effect on runtime size should be minimal.  It's also much,
much cleaner than the alternatives -- if we instead had ObjRef's
keeping count, we would have to allocate separate counters for each,
and each would have to have its own pseudo-ref's, and then when you
deactivate a ObjTableEntry you'd have to notify each of them and
they'd each have to cleverly turn off shortcut calls on themselves --
and who knows what you'd do when _setIdentity was called.  I'm willing
to try to make it work if you think the overhead is too high, but I've
worked to make it minimal and I suspect I've succeeded sufficiently.

Memory management:
   omniShortcutManager's go through the normal reference counting
mechanisms (more or less, see below) for omniObjTableEntry's and
omniObjRef's, so they're not really a problem -- they'll continue to
be deleted when the last reference drops, just now the last reference
might be held by a lingering shortcut invocation.
omniShortcutManager's and omniShortcutHolder's themselves are only
cleaned up when their owner omniObjTableEntry is deleted, but that's
correct, because that can't happen until all shortcut (and otherwise)
calls have completed, and no more are forthcoming, which together
means that no-one still holds a reference to our omniShortcutManager
and omniShortcutHolder's.  So the memory management, aside from the
clever games the invocations themselves play, is pretty easy.

Questions/Concerns (or, "Actually, I didn't know anything about omni
internals until I started working on this..."):

   Is omniObjTableEntry the right place to put this?  I've been pretty
stumped by the difference between omniObjTableEntry and
omniLocalIdentity (and, incidentally, have no clue about
omniLocalIdentity vs. omniInProcessIdentity -- I'm hoping that
handling _setIdentity correctly will handle that too).

   There's some code duplication between omniShortcutManager and
omniLocalIdentity_RefHolder -- I wanted to just have
omniShortcutManager hold a omniLocalIdentity_RefHolder, but
omniLocalIdentity_RefHolder's destructor requires that internalLock
not be held, and I can't guarantee that (because we may be ending
the shortcut "mock invocation" from inside
omniObjTableEntry::setDeactivating).  So if you look at
omniShortcutManager::_handleLastExit() and deactivate_please(),
then you'll see code quite similar to that in
~omniLocalIdentity_RefHolder, except one of them assumes that
internalLock isn't held.

   One thing I'm really not sure about is how to build the temporary
variables I need in my skeletons, to hold the return value before
returning it.  Right now I always generate code kinda like:
   <type> _objref_Foo:foo() {
     if (_shortcut_holder) {
       ...
       <type> retval = _shortcut_holder->impl->foo();
       ...
       return retval;
     } else { ... }}
but I'm not sure that simply copying the return type to be the type of
<retval> is correct in all cases -- I don't know the C++ mapping well
enough to say.  (It does seem to work fine for everything in Berlin,
which is encouraging...)

Assumptions:
  I also make a number of assumptions, all of which I believe are
correct, but should be noted.  Some are about omniORB's structure,
and some are more general:
  -- Simple assignment to pointers is atomic (ie, a read of the
pointer will get either the old value or the new value, nothing else).
This is true on every modern architecture, except some really tiny
embedded systems that only have a 16 bit memory bus (according to a
gcc hacker friend of mine).  So that should be pretty safe...
  -- Simple assignment to and reading from int's is atomic.  (Same as
for pointers)
  -- Simple readings of enum's is atomic.  (Same as for pointers) (I
use this to avoid locking in a lot of common cases in
omniShortcutManager)
  -- The servant referred to by a localIdentity is immutable over the
life of that localIdentity.
  -- I _think_ that's it :-) (This list used to be longer, but shrunk
as I refactored...)

Testing:
  I've done at least basic testing (ie, running my benchmark to make
sure calls work, no assertions fail on shutdown, etc.) with all
combinations of:
  with/without thread tracing
  with/without assembler routines (ie, with asm and mutex impls both)
  g++ 2.95/g++ 3.0 (incidentally, omni4 compiles perfectly with g++
     3.0, except that catior.cc needs to include <iomanip.h>)
I've done testing on the scale of running Berlin both with and without
thread tracing, but only with the asm routines and g++ 2.95.  (Those
recompiles are nasty...)  With these configurations, I ran Berlin
under all 3 shortcut policies, and everything worked as expected.
  I'm sure more testing should be done, though it's not clear to me
exactly how to test this -- there's no real good way to find race
conditions through testing.  Much preferable would be if you could
find the time to look over the code, and make sure I haven't done
something stupid.

As an extra bonus (for a limited time only!), the patch also includes
a few small fixes to the "unsafe" shortcut code -- some variables that
need to be declared volatile are, and a small race condition in
_enableShortcut has been fixed.

I look forward to hearing any comments :-).

-- Nathaniel

-- 
So let us espouse a less contested notion of truth and falsehood, even
if it is philosophically debatable (if we listen to philosophers, we
must debate everything, and there would be no end to the discussion).
  -- Serendipities, Umberto Eco

This email may be read aloud.

--pf9I7BMVVzbSWLtt
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="omni4-new-safe-shortcuts.patch.gz"
Content-Transfer-Encoding: base64

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
1kzQpP8HV4ReOsbkAAA=

--pf9I7BMVVzbSWLtt--