On 11/30/2010 1:43 AM, Peter Firmstone wrote:
Patricia Shanahan wrote:
Tom Hobbs wrote:
Yes, you're right.

I knew about the non-atomicity of ++, my concern was a call to reset
creeping in between the two parts of that operation.

That is a very good point.

Leaving reset unsynchronized, even with volatile, would lead to
results that would not be possible with full synchronization. Suppose
thread A is going to do a reset, and thread B is going to do an
increment, and everybody agrees the count is currently 10.
....
Ah yes, correct, my mistake, easy to stuff up isn't it? ;)

In essence I agree, unfortunately we don't know when we need the
performance, because we can't test scalability. I've only got 4 threads!

I've only got 8 threads on my largest system.

I am very, very strongly opposed to attempting performance tuning without measurement. I've seen it tried many times over several decades, and it is always a disaster. I've compared e.g. estimates of where bottlenecks will be in an operating system prepared by the OS developers to actual measurements, and I've yet to see the developers get it right. That includes my own efforts at guessing bottlenecks, before I learned that it is futile.

Without measurement, you get either get focused effort in entirely the wrong places or diffuse effort spread over the whole system. What is really needed is focused effort on a few real bottlenecks that will go way beyond any set of rules that could reasonably be applied throughout the system.

I believe the solution is to establish a working relationship with users of River who have larger systems. They have a vested interest in helping us make it more scalable.

Here are some simple tips I've found useful:

Have you measured the effectiveness of these tips on real world scalability? What sort of gain do you see?

There may also be opportunities in the area of data structure and algorithm scalability. For example, TaskManager uses an ArrayList to represent something that is basically a FIFO with some reordering. That is a good idea if, and only if, the queue lengths are always very short even on large systems. However, I have no idea whether TaskManager queue lengths tend to increase on large systems or not.

  1. If all mutators are atomic and don't depend on previous state, a
     volatile reference or field may be sufficient, but now we have
     concurrency utilities, why not use an atomic reference or field
     instead? Then if we find we later need a method based on previous
     state, it's easily proven correct.

Do we have the concurrency utilities? The java.util.concurrent packages are all "Since 1.5", and some of their classes are "Since 1.6". We can only use them if we are abandoning any chance of River running with a 1.4 rt.jar.

To my mind, the advances in java.util and its sub-packages are a really strong motivation for getting to 1.5 or, better, 1.6 ASAP.

Currently, a quick grep indicates java.util.concurrent is only used in ./qa/src/com/sun/jini/qa/harness/HeartOfTheMachine.java, which is part of the QA infrastructure, not the production system.

...

Have you got any examples of a formal proof of correctness? Just out of
curiosity?

Unfortunately, the proofs of correctness I've written that related to concurrency were based on confidential data and written on the job when I was working as a performance architect for Cray Research and Sun Microsystems.

I do have some coursework proofs from the UCSD Design of Algorithms graduate course. I'll dig out an example to send to you directly.

Proof of correctness of large systems is a research topic. I'm talking about looking very narrowly at a class that has been shown to be performance-critical and is being subjected to special performance tuning that uses risky techniques such as volatile.

Patricia

Reply via email to