Re: A Lock-Free Hash Table - Cliff Click

Pete Soper <Pete.Soper-UdXhSnd/[email protected]>
Newsgroups gmane.org.user-groups.trijug.juglist
Message-ID <[email protected]>
Shawn Hartsock wrote:
> My apologies if you've all already seen this.
>
> ...floating around on Slashdot right now:
> http://video.google.com/videoplay?docid=2139967204534450862
>
>   
Cliff was the technical lead on the Hotspot "server compiler" (aka 
"compiler2") feature, and wrote a large portion of this code. He also 
dictated key architectural aspects of the server compiler, such as a 
novel intermediate representation ("sea of nodes"). Many aspects of 
Cliff's compiler technology are bona fide "state of the art", as the 
timing of his academic work and the need for an advanced dynamic 
compiler for Java was very fortunate. Cliff continues to improve this 
compiler technology and  maintains a collaborative relationship with the 
Sun Hotspot team in a good example of "coopetition" between the two 
companies technical staff.
> In summary Dr. Cliff Click has written a concurrent data structure
> that gets around what many considered intrinsic barriers to
> multi-threaded programming. His talk is very accessible and he makes
> an interesting use of a Finite State machine as proof-of-correctness.
> I'd love to hear this groups take on Azul and these techniques. I'm
>   
IMO it's the very definition of high tech software/hardware cooperation, 
and a distinctive approach to highlylinear scaling. (By highly linear 
scaling I mean, for example, 100X  performance with 100 processors and 
100 threads sharing a task. Crappy scaling would be, for example, 2X 
performance with 3 processors & threads and 2.5X with 10 processors & 
threads).

Rather than a relatively small number of blinding-fast processors and 
collections of apps that tend to not depend on more than small 
concurrency levels (e.g. 2-4) anyway,  the Azul system combines a 
relatively large number of more modest processors combined with very 
efficient synchronization. By Amdahl's Law this pushes the scaleability 
curve way out. So application developers are encouraged to design 
applications that can efficiently take advantage of high levels of 
concurrency (possibly up to what I think is the current cpu limit for 
Azul: 768!) A key piece of the Azul Java environment is brutally fast 
heap management with special hardware assist, which can aid applications 
that aren't at all concurrent per se, but may churn through objects at a 
high rate. And an app that does depend on concurrency must also exist 
with a very efficient heap to avoid memory management being a bottleneck.

There is a bit of marketing spin in Cliff's talk. :-) For example, early 
on he mentions that the java.util.concurrent.ConcurrentHashMap "has 16 
stripes" and suggests it's just not up to the task (of heavy duty 
concurrent apps). But 16 is just  a default: ConcurrentHashMap is highly 
tunable for multiple goals and tradeoffs. I think Cliff's main point is 
that Azul sets the bar higher by virtue of very efficient concurrent 
primitives apps can build upon. But I don't know all the detailed 
differences between j.u.c.ConcurrentHashMap and Cliff's map design: the 
latter could be superior in every way, for all I know. On the other hand 
I suspect if this is true Doug Lea and friends won't let it stay true 
for long. :-)
> also curious if many Java programmers in the triangle have to deal
> with concurrency themselves or if they happily let Spring/J2EE take
> care of the issues by marking things transactional.
>
> The interesting bit in Click's talk (at least to me) is that he has a
> concurrent data structure that is thread safe and doesn't make use of
> a single lock or synchronize. (If he is I'm missing it and would love
>   
This is not quite correct. An early slide shows that "bounded spin 
locks", abortable locks, an atomic CAS (compare and swap) primitives all 
somehow qualify as parts of his "lockless system."  To draw a practical 
analogy, Cliff would seem to want his audience to think of a garden 
variety spin lock being similar to Houdini in his chains, suspended 
upside down in the water-filled chamber, while his synchronization 
techniques with bounded locks, fenceless CAS, etc are more like bumping 
your forehead on a door that was  slammed shut just before you got to 
it: you recover and grab the knob and get through the door relatively 
faster than Houdini can possibly get out of his chains. IMO both 
scenarios involve locks, but relative to the cost of Houdini's 
constraints a simple "one at a time" door or turnstile could be 
considered "relatively lock free."

The truth is that these things are indeed relative and either their is 
synchronization or not: optimization of frequency and overhead is what's 
being discussed. Even a single, simple (fenceless) CAS (atomic compare 
and swap) instruction executing in the context of a lot of contending 
threads constitutes a "got through the door" experience for one thread 
and "bounced my nose off the slammed-shut door" experience for all the 
others arriving at the same spot at the same time (with the same "door 
address"). And this simultaneous arrival happens *a lot more* than 
people might think, and quite often constitutes a measurable factor 
limiting performance. Unsuccessful threads have to stop and wait before 
the hardware will allow their CAS mutation.  This contention seems like 
"nothing", but adds to the accounting of the fraction of overall work 
made up of serialized work and that determines absolute maximum scaling 
in accord with Amdahl's Law. 

And with a fenced CAS the effect can be dramatic, as  current processor 
designs tend to have a lot of concurrent cache and memory operations "on 
the fly" at any moment. When the fenced CAS is encountered the fence 
semantics are kind of like several running school kids crossing a field 
and suddenly coming to a turnstile. These kids have an absolute pecking 
order: they must go through the turnstile in order. And until they are 
all over the CAS itself cannot complete. And memory operations (register 
to L1, L1 to L2, L2, to L3, L3 to "main memory") are disgustingly slow 
relative to the raw speed of CPU operations these days. Meanwhile, the 
cache and memory states of other threads are distrupted by the fence 
(again, if the same logical location is involved), often causing more 
"mad rushes for the turnstile" when each can finally execute the fenced 
CAS.

Adding a single fenced CAS to the innermost guts of Java can have a big 
effect on performance in a concurrent context. One example is the 
transition between native (e.g. JNI) and Java code. There has to be 
coordination of control returning to Java code execution following 
native execution on the one hand and garbage collection "safepoints" to 
do with guarantees about what can and cannot be mutating on the other. 
This coordination used to use fences in Hotspot, penalizing every thread 
with every transition. But now a clever trick with virtual memory page 
privileges is used so that if there is no contention the threads don't 
have to suffer any penalty. If there is simultaneous garbage collection 
going on a cost will be imposed automatically. The value of this 
optimization is quite small to immeasurable for a single threaded app. 
But with a JVM running a thousand threads it is noticeable. :-)

-Pete

> to be corrected.)
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.