Re: JavaMemoryModel: fusing synch blocks

From: Cliff Click (cliff.click@Eng.Sun.COM)
Date: Fri Feb 02 2001 - 11:35:59 EST


Doug Lea wrote (and Cliff editted out big chunks):

> The basic idea is that you'd like to allow fusion of blocks locking on
> the same lock. That is:
> synchronized(x) { a(); }
> synchronized(x) { b(); }
> may be transformed into
> synchronized(x) { a(); b(); }
>
> Rule 2: No block may be fused with itself.
>
> T1 T2
> for (;;) { synchronized(x) { a = 1; }
> synchronized(x) {
> if (a != 0) break;
> }
> }
>
> It's clearly a bad idea to transform T1's code to one in which the
> block is fused with itself:
>
> synchronized(x) {
> for (;;) {
> if (a != 0) break;
> }
> }
>
> ... since T1's loop that was previously guaranteed to terminate if T2
> ever reached its assignment can now lockout T2 and livelock T1.
>
> (On the other hand, loop unrollings should be allowed to fuse unrolled
> segments.)

I understand your intent, but "loop unrollings should be allowed to fuse
unrolled segments" looks like it contradicts Rule 2. Fer instance, if one
runs over to SciMarks and looks at the MonteCarlo simulation, one
sees stuff like:

  for( int i = 0; i < 1bazillion; i++ ) {
    sync(global_lock) {
      obtain psuedo random # and update seed under lock
    }
    simulate_using_psuedo_random_value
  }

which one clearly wants to unroll as:

  for( int i = 0; i < 1bazillion; i+=2 ) {
    sync(global_lock) {
      obtain psuedo random # and update seed under lock
    }
    simulate_using_psuedo_random_value
    sync(global_lock) {
      obtain psuedo random # and update seed under lock
    }
    simulate_using_psuedo_random_value
  }

then fuse the locks. Or perhaps do unroll-and-jam:

  for( int i = 0; i < 1bazillion; i+=8 ) {
    for( int j = 0; j < 8; j++ ) {
      sync(global_lock) {
        obtain psuedo random # and update seed under lock
      }
      simulate_using_psuedo_random_value
    }
  }

Now the inner loop is known to be short duration, so fusing the lock
with itself:

  for( int i = 0; i < 1bazillion; i+=8 ) {
    sync(global_lock) {
      for( int j = 0; j < 8; j++ ) {
        obtain psuedo random # and update seed under lock
        simulate_using_psuedo_random_value
      }
    }
  }

In any case, having a Rule 2 flatly deny fusing a lock with itself isn't what
you really want, since you've already come up with exceptions to it. Instead
I like your fairness guarentee rule. And hoisting a lock outside a huge
(but finite) loop should be allowed but stupid - it falls under the "quality of
implementation" rules that C compilers hit all the time.

Cliff

-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:29 EDT