There’s a lot of noise about transactional memory, thought I should do a bit of research. Having read a number of papers I’m left wondering just what all the racket is for. At least for me the benefits are unclear.

Let’s consider this paper which discusses amongst other things “transactifying” Berkeley Db (a piece of software I know quite well). It contains a comparison of the original version of Db’s locking system (which used a global lock) and the paper’s authors’ modified version. Initial changes were to replace all uses of the global lock with a set of transactions. A test was run and the transactional version was worse all around than the original – ooops.

The root cause boiled down to three issues:

  1. False sharing – a problem which occurs when variables accessed by different threads happen to fall in the same cacheline – this was solved with a traditional approach known as padding.
  2. Statistics collection – Db collected a bunch of statistics keeping them accurate by using the global lock. Rather than address what is surely a common problem, the authors simply turned this feature off.
  3. Object pooling – the pooling associated with lock descriptors and their related objects had to be changed from single linked-lists to collections of linked-lists to improve potential for concurrent access.

The tests were re-run and beyond a certain level of scale the transactional memory version was now better but wait, there’s a problem. Notice that all the work being done to make the transactional version better is broadly the same as the work one would do to make the locking version better. How much of the scalability gain is due to better concurrent structure and how much is down to transactional memory? Is the work we’ve just done any simpler than what we already have to do for conventional thread/lock based systems?

Another under-discussed factor across many papers in this area is related to the assertion that transactional memory is better than locking due to it being more efficient in the non-conflict case. However many modern lock primitives are now also optimized for this circumstance.

What about the fact that, one must make sure to correctly isolate the atomic actions in a system and bound them appropriately with transactions just as one currently does with locking? We still have to make sure we do that consistently across the entire system or risk the usual concurrency debugging nightmares.

Many of the transactional memory systems appear to be based on optimistic approaches – does that make sense for all algorithms and systems we might build? Other transactional systems have evolved to provide both optimistic and pessimistic options (in an attempt to cover all design possibilities) and the programmer must make the appropriate choice for their application. Will transactional memory systems also need to move this way and if so, how will the programmer work with that?

Asserting Order

I’m not going to write-off transactional memory but it seems that should it turn out to be more scalable than the conventional lock-based approaches we use:

  1. It’s really not much simpler to program with.
  2. It’s no use in the distributed case.

Meanwhile:

  1. There are other approaches around that do work across both multi-core and multi-box/distributed cases with little change (some would argue the amount of change is zero but I don’t buy that).
  2. Dealing with concurrency is about much more than whether you use locks or transactions.

Technorati Tags: , , ,

  • Share/Bookmark
3 Responses to “Incoherent Ramblings”
  1. Not SPJ says:

    http://en.wikipedia.org/wiki/Software_transactional_memory#Implementation_issues

    STM is a silver bullet that doesn’t work. It just trades off some obvious categories of bugs for even worse race conditions.

    Besides that, to atomically verify its log it has to do some type of locking anyway on everything you wrote AND everything you simply READ. It actually doesn’t eliminate any of the usual problems, it just moves them down a level where you don’t see them — sweeping them under the rug, as it were; AND it gives you a whole new set of Heisenbugs to torture you with.

  2. Daniel Lyons says:

    Much of what we’re hearing about STM comes from the surprising current energy for functional programming. Locking being a side-effect, it doesn’t fit well into the functional paradigm. STM is particularly compelling because it happens to be a formalism that fits well into Haskell’s monad system, which you already have to use to do anything stateful in the language. STM is certainly easier to program in Haskell than a threading/locking system, but one has to ask whether or not this is just pushing the complexity into the compiler. Though Haskell is one of a very few languages where I would actually trust the implementors to put something that difficult into the compiler and solve it once; they are, after all, already doing some incredibly hard work in there.

    Apart from that there is a general distaste for threading and locking. There is a famous proof by Hans Boehm that library-based threading models cannot produce bug-free executables because certain compiler optimizations which are safe and retain meaning in serial programs produce bugs in parallel ones. People are searching for something to defect to.

  3.