Slide 1

Slide 1 text

Copyright 2014 FUJITSU LIMITED Javaでトランザクショナルメモ リを使う 2014.5.18 数村 憲治 JJUG CCC 2014 Spring

Slide 2

Slide 2 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 1 Copyright 2014 FUJITSU LIMITED

Slide 3

Slide 3 text

2 Copyright 2014 FUJITSU LIMITED JavaVMロック機構の進化 第一世代 ヘビーロック 第二世代 シンロック 第三世代 バイアスロック 第四世代 ??? JDK1.0-1.2 JDK1.3.1 HotSpot VM JDK5.0 HotSpot VM

Slide 4

Slide 4 text

競合と共有(定義)  ロック競合とは 複数のスレッドが同時 に同じロックを取る  ロック共有とは 複数のスレッドが同じ ロックを使用する 3 Copyright 2014 FUJITSU LIMITED スレッドA スレッドB ロックX獲得 ロックX待ち ロックXの競合 ロック競合している例 共有しているが競合していない例 スレッドA スレッドB ロックX獲得 ロックX解放 ロックX獲得 CS 実 行 CS 実 行 CS 実 行

Slide 5

Slide 5 text

競合と共有(定義)  データ競合とは 複数のスレッドが同じ データにアクセスする こと、あるいは、アク セスするためのロック 競合 4 Copyright 2014 FUJITSU LIMITED synchronized(array) { array[1] = 2; } synchronized(array) { array[2] = 4; } スレッドA スレッドB ロック競合しているが データ競合していないコード例 ロック競合しているが データ競合していない例 スレッドA スレッドB ロックX獲得 ロックX待ち ロックの競合 アクセスY アクセスZ ロックX解放 ロックX獲得 データ競合なし CS 実 行 CS 実 行

Slide 6

Slide 6 text

ヘビーロック  OSのロック関数(pthread_mutex_lock/unlock 等)を使用  実装が簡単なため、初期のJVMで使用  オブジェクト毎にmutexを作成・保持する必 要がある 5 Copyright 2014 FUJITSU LIMITED 管理ヘッダ mutex Javaオブジェクト mutex_t if(obj->mutex == null) { obj->mutex = malloc(…); … } pthread_mutex_lock(&obj->mutex); 本来の オブジェクト データ synchornizeの実装例

Slide 7

Slide 7 text

シンロック  ほとんどのロックは競合してない  CAS(Compare and Swap)で十分  マルチコア・メニーコアCPUでは、CASのコ ストはバカにならない 6 Copyright 2014 FUJITSU LIMITED ロック ビット Javaオブジェクト 管理ヘッダ mov 0, %R2 ld [ロックビット], %R1 cas [ロックビット], %R1, %R2 cmp %R1, %R2 jne ヘビーロック 通常処理 0:ロック 1:アンロック シンロック実装例

Slide 8

Slide 8 text

バイアスロック  ほとんどのロックは共有されていない 特定のスレッド使うならロックする必要はない  最初(バイアスされていない時)だけCAS  そのあとはLoad&Compare 7 Copyright 2014 FUJITSU LIMITED ld [バイアス情報], %R1 cmp %R1, 自分自身のスレッド jne バイアス無効処理 通常処理 バイアスされている場合の 実装例 StringBuffer sb = new StringBuffer(); sb.append(“abc”); sb.append(“def”); String str = sb.toString(); return str; バイアスロックの有効例

Slide 9

Slide 9 text

java.util.concurrentパッケージ  JDK5.0から導入  synchronizeより柔軟なロック 8 Copyright 2014 FUJITSU LIMITED import java.util.concurrent.locks.ReentrantLock; ReentrantLock lock = new ReentrantLock(); … public void m() { lock.lock(); try { //クリティカルセクションの実行 } finally { lock.unlock(); } tryLock() isLocked() getOwner() 使用例 便利なAPI (ReentrantLock) 便利なクラス ReadWriteLock Semaphore AtomicInteger

Slide 10

Slide 10 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 9 Copyright 2014 FUJITSU LIMITED

Slide 11

Slide 11 text

トランザクショナルメモリとは  楽観的ロック  とりあえず、ロックはしない  実行しているうちに、データ競合があった ら、それまでの実行結果を破棄( アボート )して、最初の状態にもどる(ロールバッ ク)  最後までデータ競合がなければ、結果を確 定する(コミット) 10 Copyright 2014 FUJITSU LIMITED

Slide 12

Slide 12 text

悲観的ロックと楽観的ロック 11 Copyright 2014 FUJITSU LIMITED 楽観的ロック 非観的ロック スレッド1 スレッド2 スレッド3 スレッド4 ロック ロック ロック ロック クリティカルセクションの実行はシリアライズ スレッド1 スレッド2 スレッド3 スレッド4 ロ ッ ク な し クリティカルセクションの実行は並行

Slide 13

Slide 13 text

HTMとSTM  トランザクショナルメモリ(TM)をハード で実現するのをHTM、ソフトで実現するの をSTMと呼ぶ。  HTMの実装例 IBM System z (zEC12) Intel Haswell Microarchitecture  STMの実装例 Scala Haskell 12 Copyright 2014 FUJITSU LIMITED

Slide 14

Slide 14 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 13 Copyright 2014 FUJITSU LIMITED

Slide 15

Slide 15 text

TSX  Intel® Transactional Synchronization Extension IntelアーキテクチャでのHTM実装 Haswellで利用可能 HLEとRTMの2種類  Hardware Lock Elision 従来(mutex)方式と互換インタフェース  Restricted Transaction Memory 新しいインタフェース 14 Copyright 2014 FUJITSU LIMITED

Slide 16

Slide 16 text

HLE  従来のmutex_lock/mutex_unlockの形式でそ のまま置き換えられる  アボートしたら、自動的にリトライ 15 Copyright 2014 FUJITSU LIMITED mov $1, %eax RETRY: xacquire xchg mutex, %eax test %eax, %eax jne RETRY xrelease mov $0, mutex mutex_lock(&mutex); mutex_unlock(&mutex); クリティカルセクションの実行 クリティカルセクションの実行 従来(mutex) HLE

Slide 17

Slide 17 text

GCC4.8からHLEサポート 16 Copyright 2014 FUJITSU LIMITED #include void lock_hle_gcc(int *mutex) { while (__atomic_exchange_n(mutex, 1, __ATOMIC_ACQUIRE|__ATOMIC_HLE_ACQUIRE)) _mm_pause(); } void unlock_hle_gcc(int *mutex) { __atomic_clear(mutex, __ATOMIC_RELEASE|__ATOMIC_HLE_RELEASE); } 以下のような関数を自分で用意する(fallbackなし) int mutex = 0; void func() { lock_hle_gcc(&mutex); // クリティカルセクションの実行 unlock_hle_gcc(&mutex); クリティカルセクションを 上記2関数で挟む

Slide 18

Slide 18 text

GCC4.8からHLEをサポート 17 Copyright 2014 FUJITSU LIMITED 0000000000000000 : 0: ba 01 00 00 00 mov $0x1,%edx 5: eb 0b jmp 12 7: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 10: f3 90 pause 12: 89 d0 mov %edx,%eax 14: f2 87 07 xacquire xchg %eax,(%rdi) 17: 85 c0 test %eax,%eax 19: 75 f5 jne 10 1b: f3 c3 repz retq 1d: 0f 1f 00 nopl (%rax) 0000000000000020 : 20: f3 c6 07 00 xrelease movb $0x0,(%rdi) 24: c3 retq ディスアセンブルするには、新しいobjdump(binutils)が必要

Slide 19

Slide 19 text

RTM  アボートした時のハンドラ―を自分で書く 必要あり 18 Copyright 2014 FUJITSU LIMITED RETRY: xbegin FAIL cmp mutex, $0 jz OK FAIL: # goto RETRY or SLOWPATH SLOWPATH: # original code OK: ret cmp mutex, $0 jne SLOWPATH xend ret SLOWPATH: # original code ロックコード アンロックコード

Slide 20

Slide 20 text

いつアボートするか  トランザクションが長い  I/Oが入る  OSによるスレッドコンテキストスイッチ  特殊な命令を実行(CPUID/XABORT)  ネストが深すぎる  L1キャッシュラインの競合 19 Copyright 2014 FUJITSU LIMITED

Slide 21

Slide 21 text

Haswellのキャッシュ  L1 Instruction Cache 32KB 8-way  L1 Data Cache 32KB 8-way コアごと(スレッドで共有)  L2 Unified Cache 256KB 8-way コアごと(スレッドで共有)  キャッシュライン 64B 20 Copyright 2014 FUJITSU LIMITED 64バイト 64バイト 64バイト 64バイト L1 Data Cache 64個 8-way

Slide 22

Slide 22 text

キャッシュラインの競合  TSXでは、L1キャッシュラインでデータ競合 を検出 21 Copyright 2014 FUJITSU LIMITED xbegin FAIL mov (0x1000), %eax xend スレッドA xbegin FAIL mov %eax, (0x1010) xend スレッドB 0x1000 0x1010 0x1004 0x1008 0x1040 アドレス 同 一 キ ャ ッ シ ュ ラ イ ン 競合

Slide 23

Slide 23 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 22 Copyright 2014 FUJITSU LIMITED

Slide 24

Slide 24 text

Javaでの実装案  synchronizeの実装として使う  APIとして提供  特定ライブラリでの実装 23 Copyright 2014 FUJITSU LIMITED

Slide 25

Slide 25 text

synchronizeの実装  アプリの修正が不要  個別に指定できない 競合あるところはTMは向いていないので、従来 実装を使いたい 競合のないところは、TM実装を使いたい  実装するのがたいへん JVM(HotSpot)の中でかなりの部分に影響 24 Copyright 2014 FUJITSU LIMITED

Slide 26

Slide 26 text

APIとして提供  アプリ修正が必要  選択的に使用可能  使う側がどういう場合にTMが向いているか 理解している必要あり  使用方法はReentrantLockと同じ  実装はsyhchronizeほどではないが、比較的 たいへん。 25 Copyright 2014 FUJITSU LIMITED

Slide 27

Slide 27 text

特定ライブラリでの実装  アプリ修正は不要  使いたいところで使えない  例 java.util.HashMap/ArrayList/LinkedList 26 Copyright 2014 FUJITSU LIMITED table HashMap Entryテーブル Key Value Key Value

Slide 28

Slide 28 text

API方式での実装 27 Copyright 2014 FUJITSU LIMITED public final class HTM { private ByteBuffer data; private long mutex_addr; public HTM() { data = ByteBuffer.allocateDirect(64); mutex_addr = nativeAddress(data); } public void lock() { lockRTM(mutex_addr); } public void unlock() { unlockRTM(mutex_addr); } static private native void lockRTM(long addr); static private native void unlockRTM(long addr); 使用方法 HTM htm = new HTM(); htm.lock(); // クリティカル //セクションの実行 htm.unlock();

Slide 29

Slide 29 text

HTMクラスの構造 28 Copyright 2014 FUJITSU LIMITED ByteBuffer data HTM 64バイト long mutex_addr Javaヒープ Cヒープ DirectByteBuffer ・・・ long address allocateDirect(64) mutex

Slide 30

Slide 30 text

ネイティブメソッド(C) 29 Copyright 2014 FUJITSU LIMITED #include void java_htm_lock_rtm(jlong); void java_htm_unlock_rtm(jlong); JNIEXPORT void JNICALL Java_HTM_lockRTM(JNIEnv *env, jclass kl, jlong add) { java_htm_lock_rtm(add); } JNIEXPORT void JNICALL Java_HTM_unlockRTM(JNIEnv *env, jclass kl, jlong add) { java_htm_unlock_rtm(add); }

Slide 31

Slide 31 text

ネイティブメソッド(asm) 30 Copyright 2014 FUJITSU LIMITED # void java_htm_lock_rtm(jlong) java_htm_lock_rtm: movl $10, %ecx #retry count .RETRY: xbegin .FAIL cmpl $0, (%rdi) jz .OK xabort $0xfe .FAIL: pause dec %ecx cmpl $0, %ecx jz .SLOWPATH jmp .RETRY .SLOWPATH: xor %edx, %edx inc %edx xor %eax, %eax lock cmpxchgl %edx, (%rdi) jne .SLOWPATH .OK: ret # void java_htm_unlock_rtm(jlong) java_htm_unlock_rtm: cmpl $0, (%rdi) jz .END movl $0, (%rdi) ret .END: xend ret

Slide 32

Slide 32 text

データ競合なしプログラム  本来ロックを取る必要のないプログラムで のベンチマーク  一定量(500,000,000回)スレッドローカルな 変数をインクリメントする  スレッド数を1から8まで増やす  各スレッドに均等な処理量を分割する  各スレッドの処理時間の平均を求める  「排他なし」、「synchronized」、 「ReentrantLock」「HTM」の4パターン 31 Copyright 2014 FUJITSU LIMITED

Slide 33

Slide 33 text

データ競合なしプログラム 32 Copyright 2014 FUJITSU LIMITED class LockNone extends Test { LockNone(long amount) { this.amount = amount; } void doIt() { count++; } } abstract class Test implements Runnable { long count; long time; long amount; public void run() { count = 0; long start = System.currentTimeMillis(); while (count < amount) { doIt(); } long end = System.currentTimeMillis(); time = (end-start); } } 排他なし

Slide 34

Slide 34 text

データ競合なしプログラム 33 Copyright 2014 FUJITSU LIMITED class LockSync extends Test { Object lock; LockSync(long amount, Object lock) { this.amount = amount; this.lock = lock; } void doIt() { synchronized (lock) { count++; } } } synchronized使用

Slide 35

Slide 35 text

データ競合なしプログラム 34 Copyright 2014 FUJITSU LIMITED class LockConc extends Test { ReentrantLock lock; LockConc(long amount, ReentrantLock lock) { this.amount = amount; this.lock = lock; } void doIt() { lock.lock(); count++; lock.unlock(); } } ReentrantLock使用

Slide 36

Slide 36 text

データ競合なしプログラム 35 Copyright 2014 FUJITSU LIMITED class LockRTM extends Test { HTM htm; LockRTM(long amount, HTM htm) { this.amount = amount; this.htm = htm; } void doIt() { htm.lock(); count++; htm.unlock(); } } HTM使用

Slide 37

Slide 37 text

データ競合なし(結果) 36 Copyright 2014 FUJITSU LIMITED 1スレッドあたりの平均処理時間 JDK1.7.0_51 Intel Xeon E3-1270 v3 3.5GHz Red Hat Enterprise Linux Server release 6.5 (Santiago)

Slide 38

Slide 38 text

ネイティブメソッド呼出し  ネイティブメソッドの呼び出しはコストが 高い  性能高速化のために、Javaでかけるコード をCにしても、速くなるとは限らない 37 Copyright 2014 FUJITSU LIMITED Java メソッド ネイティブ メソッド スタブ コード 直接呼べない

Slide 39

Slide 39 text

スタブコード(unlockRTM) 38 Copyright 2014 FUJITSU LIMITED Decoding compiled method 0x00007f12dd05ebd0: Code: [Disassembling for mach='i386:x86-64'] [Entry Point] # {method} 'unlockRTM' '(J)V' in 'HTM' # parm0: rsi:rsi = long # [sp+0x50] (sp of caller) 0x00007f12dd05ed60: mov 0x8(%rsi),%r10d 0x00007f12dd05ed64: cmp %r10,%rax 0x00007f12dd05ed67: je 0x00007f12dd05ed78 0x00007f12dd05ed6d: jmpq 0x00007f12dd037960 ; {runtime_call} 0x00007f12dd05ed72: nopw 0x0(%rax,%rax,1) [Verified Entry Point] 0x00007f12dd05ed78: mov %eax,-0x14000(%rsp) 0x00007f12dd05ed7f: push %rbp 0x00007f12dd05ed80: mov %rsp,%rbp 0x00007f12dd05ed83: sub $0x40,%rsp 0x00007f12dd05ed87: mov %rsi,%rdx 0x00007f12dd05ed8a: movabs $0xdff84370,%r14 ; {oop(a 'java/lang/Class' = 'HTM')} 0x00007f12dd05ed94: mov %r14,0x30(%rsp) 0x00007f12dd05ed99: lea 0x30(%rsp),%r14 0x00007f12dd05ed9e: mov %r14,%rsi ; OopMap{[48]=Oop off=65} 0x00007f12dd05eda1: movabs $0x7f12dd05eda1,%r10 ; {section_word} 0x00007f12dd05edab: mov %r10,0x1c0(%r15) 0x00007f12dd05edb2: mov %rsp,0x1b8(%r15) 0x00007f12dd05edb9: cmpb $0x0,0x8ef495a(%rip) # 0x00007f12e5f5371a ; {external_word} 0x00007f12dd05edc0: je 0x00007f12dd05edfa 0x00007f12dd05edc6: push %rsi 0x00007f12dd05edc7: push %rdx 0x00007f12dd05edc8: movabs $0xdafd0040,%rsi ; {oop({method} 'unlockRTM' '(J)V' in 'HTM')} 0x00007f12dd05edd2: mov %r15,%rdi 0x00007f12dd05edd5: test $0xf,%esp 0x00007f12dd05eddb: je 0x00007f12dd05edf3 0x00007f12dd05ede1: sub $0x8,%rsp 0x00007f12dd05ede5: callq 0x00007f12e59c4230 ; {runtime_call} 0x00007f12dd05edea: add $0x8,%rsp 0x00007f12dd05edee: jmpq 0x00007f12dd05edf8 0x00007f12dd05edf3: callq 0x00007f12e59c4230 ; {runtime_call} 0x00007f12dd05edf8: pop %rdx 0x00007f12dd05edf9: pop %rsi 0x00007f12dd05edfa: lea 0x1d8(%r15),%rdi 0x00007f12dd05ee01: movl $0x4,0x250(%r15) 0x00007f12dd05ee0c: callq 0x00007f12da7ef660 ; {runtime_call} 0x00007f12dd05ee11: vzeroupper 0x00007f12dd05ee14: movl $0x5,0x250(%r15) 0x00007f12dd05ee1f: mov %r15d,%ecx 0x00007f12dd05ee22: shr $0x4,%ecx 0x00007f12dd05ee25: and $0xffc,%ecx 0x00007f12dd05ee2b: movabs $0x7f12e61ac000,%r10 ; {external_word} 0x00007f12dd05ee35: mov %ecx,(%r10,%rcx,1) 0x00007f12dd05ee39: cmpl $0x0,0x8efd83d(%rip) # 0x00007f12e5f5c680 ; {external_word} 0x00007f12dd05ee43: jne 0x00007f12dd05ee57 0x00007f12dd05ee49: cmpl $0x0,0x30(%r15) 0x00007f12dd05ee51: je 0x00007f12dd05ee74 0x00007f12dd05ee57: mov %r15,%rdi 0x00007f12dd05ee5a: mov %rsp,%r12 0x00007f12dd05ee5d: sub $0x0,%rsp 0x00007f12dd05ee61: and $0xfffffffffffffff0,%rsp 0x00007f12dd05ee65: callq 0x00007f12e5a655a0 ; {runtime_call} 0x00007f12dd05ee6a: mov %r12,%rsp 0x00007f12dd05ee6d: mov 0x8ed8f3c(%rip),%r12 # 0x00007f12e5f37db0 ; {external_word} 0x00007f12dd05ee74: movl $0x8,0x250(%r15) 0x00007f12dd05ee7f: cmpl $0x1,0x27c(%r15) 0x00007f12dd05ee8a: je 0x00007f12dd05ef13 0x00007f12dd05ee90: cmpb $0x0,0x8ef4883(%rip) # 0x00007f12e5f5371a ; {external_word} 0x00007f12dd05ee97: je 0x00007f12dd05eecd 0x00007f12dd05ee9d: movabs $0xdafd0040,%rsi ; {oop({method} 'unlockRTM' '(J)V' in 'HTM')} 0x00007f12dd05eea7: mov %r15,%rdi 0x00007f12dd05eeaa: test $0xf,%esp 0x00007f12dd05eeb0: je 0x00007f12dd05eec8 0x00007f12dd05eeb6: sub $0x8,%rsp 0x00007f12dd05eeba: callq 0x00007f12e59c4380 ; {runtime_call} 0x00007f12dd05eebf: add $0x8,%rsp 0x00007f12dd05eec3: jmpq 0x00007f12dd05eecd 0x00007f12dd05eec8: callq 0x00007f12e59c4380 ; {runtime_call} 0x00007f12dd05eecd: movabs $0x0,%r10 0x00007f12dd05eed7: mov %r10,0x1b8(%r15) 0x00007f12dd05eede: movabs $0x0,%r10 0x00007f12dd05eee8: mov %r10,0x1c0(%r15) 0x00007f12dd05eeef: mov 0x38(%r15),%rcx 0x00007f12dd05eef3: movq $0x0,0x100(%rcx) 0x00007f12dd05eefe: leaveq 0x00007f12dd05eeff: cmpq $0x0,0x8(%r15) 0x00007f12dd05ef07: jne 0x00007f12dd05ef0e 0x00007f12dd05ef0d: retq 0x00007f12dd05ef0e: jmpq Stub::forward exception ; {runtime_call} 0x00007f12dd05ef13: mov %rsp,%r12 0x00007f12dd05ef16: sub $0x0,%rsp 0x00007f12dd05ef1a: and $0xfffffffffffffff0,%rsp 0x00007f12dd05ef1e: callq 0x00007f12e59c3600 ; {runtime_call} 0x00007f12dd05ef23: mov %r12,%rsp 0x00007f12dd05ef26: mov 0x8ed8e83(%rip),%r12 # 0x00007f12e5f37db0 ; {external_word} 0x00007f12dd05ef2d: jmpq 0x00007f12dd05ee90 0x00007f12dd05ef32: hlt

Slide 40

Slide 40 text

JITコードをdisassemble  hsdis-amd64.soの場所をLD_LIBRARY_PATHに  -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 39 Copyright 2014 FUJITSU LIMITED

Slide 41

Slide 41 text

native intrinsic  ネイティブメソッドをJITが翻訳したコード のように扱う  インライン展開することで、スタブが不要 40 Copyright 2014 FUJITSU LIMITED Java ソース Cソース .class .so/.dll 翻訳 コード javac Cコンパイラ jit スタブ経由の 呼出し 同等コード アセンブラ 翻訳 コード 取込み

Slide 42

Slide 42 text

intrinsicコード(lock) 41 Copyright 2014 FUJITSU LIMITED instruct htm_lock_rtm( memory adr, rax_RegI result, rcx_RegI tmp) %{ match(HtmRtmLock adr); ins_encode %{ Label retry, fail, ok, slowpath; __ movl($tmp$$Register, 10); __ bind(retry); __ xbegin(fail); __ cmpl($adr$$Address, 0); __ jccb(Assembler::equal, ok); __ xabort(0xfe); __ bind(fail); __ pause(); __ decrementl($tmp$$Register); __ cmpl($tmp$$Register, 0); __ jccb(Assembler::equal, slowpath); __ jmp(retry); __ bind(slowpath); __ movl($tmp$$Register, 1); __ movl($result$$Register, 0); __ lock(); __ cmpxchgl($tmp$$Register, $adr$$Address); __ jccb(Assembler::notEqual, slowpath); __ bind(ok); hotspot/src/cpu/x86/vm/x86_64.ad

Slide 43

Slide 43 text

intrinsicコード(unlock) 42 Copyright 2014 FUJITSU LIMITED instruct htm_unlock_rtm(memory adr, rax_RegI result) %{ match(HtmRtmUnlock adr); ins_encode %{ Label end, done; __ cmpl($adr$$Address, 0); __ jccb(Assembler::equal, end); __ movl($adr$$Address, 0); __ jmp(done); __ bind(end); __ xend(); __ bind(done); hotspot/src/cpu/x86/vm/x86_64.ad

Slide 44

Slide 44 text

データ競合なし(結果) 43 Copyright 2014 FUJITSU LIMITED 1スレッドあたりの平均処理時間 JDK1.7.0_51 Intel Xeon E3-1270 v3 3.5GHz Red Hat Enterprise Linux Server release 6.5 (Santiago)

Slide 45

Slide 45 text

データ競合あるかもプログラム  ArrayListアクセス時にロックを取るプログ ラムでのベンチマーク  全部で一定回数(100,000,000回)、ArrayListの 連続した2要素を入れ替える  入れ替える場所はランダムに決める  配列要素は十分大きい  スレッド数を1から8まで増やす  各スレッドに均等な処理量を分割する  各スレッドの処理時間の平均を求める 44 Copyright 2014 FUJITSU LIMITED

Slide 46

Slide 46 text

データ競合あるかもプログラム 45 Copyright 2014 FUJITSU LIMITED static long AMOUNT = 100_000_000L; static int ARRAY_SIZE = 131_072; static ArrayList alist = new ArrayList<>(ARRAY_SIZE); abstract class Test implements Runnable { long count; long time; long amount; long seed; public void run() { count = 0; long start = System.currentTimeMillis(); while (count < amount) { int n1 = nextInt(ARRAY_SIZE); int n2 = n1+1; if (n2 == ARRAY_SIZE) n2 -= 2; doIt(n1, n2); count++; } long end = System.currentTimeMillis(); time = (end-start); } void swap(int n1, int n2) { Object o1 = alist.get(n1); Object o2 = alist.get(n2); alist.set(n1, o2); alist.set(n2, o1); } int nextInt(int n) { long nextseed = (seed * 0x5deece66dL + 0xbL) & ((1L << 48) - 1); long rnd31 = nextseed >>> (48-31); seed = nextseed; return (int) ((n * rnd31) >> 31); }

Slide 47

Slide 47 text

データ競合あるかもプログラム 46 Copyright 2014 FUJITSU LIMITED void doIt(int n1, int n2) { synchronized (lock) { swap(n1, n2); } } void doIt(int n1, int n2) { lock.lock(); try { swap(n1, n2); } finally { lock.unlock(); } } void doIt(int n1, int n2) { swap(n1, n2); } void doIt(int n1, int n2) { htm.lock(); try { swap(n1, n2); } finally { htm.unlock(); } } 排他なし HTM synchronized ReentrantLock

Slide 48

Slide 48 text

データ競合あるかも(結果) 47 Copyright 2014 FUJITSU LIMITED 1スレッドあたりの平均処理時間 JDK1.7.0_51 Intel Xeon E3-1270 v3 3.5GHz Red Hat Enterprise Linux Server release 6.5 (Santiago)

Slide 49

Slide 49 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 48 Copyright 2014 FUJITSU LIMITED

Slide 50

Slide 50 text

JDK8/9の動向  -XX:+UseRTMLocking https://bugs.openjdk.net/browse/JDK-8031320  synchronizeの実装として使用 メソッド毎に有効・無効を指定する仕組みはあ りそう  バイアスロックとは排他関係  性能は? 49 Copyright 2014 FUJITSU LIMITED

Slide 51

Slide 51 text

データ競合なし(JDK9) 50 Copyright 2014 FUJITSU LIMITED 1スレッドあたりの平均処理時間

Slide 52

Slide 52 text

目次  JavaVMにおけるロックの進化  トランザクショナルメモリ(TM)とは  Haswellでのトランザクショナルメモリ  Javaでトランザクショナルメモリを使う  JDK8/9の動向  まとめ 51 Copyright 2014 FUJITSU LIMITED

Slide 53

Slide 53 text

JavaでTMが有効なケース  ロック共有しているが、ロック競合がない バイアスロックが不向きなパターン  ロック競合はあるが、データ競合がない 本来プログラム的にはロックの必要がなく、安 心のためだけにロックを入れている  ロック競合はあるが、ほとんどデータ競合 せず、たまに競合する場合がある ArrayListのパターン 52 Copyright 2014 FUJITSU LIMITED

Slide 54

Slide 54 text

JavaでTMの効果ないケース  ロック競合がほとんど起きていない  ロック期間が長い バッファ枯渇やコンテキストスイッチ  ロック中にIOあり デバッグは難しい  ロック中にGCあり  共有しないロックを何度も使う バイアスロックがよい 53 Copyright 2014 FUJITSU LIMITED

Slide 55

Slide 55 text

Q&A 54 Copyright 2014 FUJITSU LIMITED

Slide 56

Slide 56 text

55 Copyright 2014 FUJITSU LIMITED Javaは、Oracle Corporationおよびその子会社、関連会社の米国および その他の国おける登録商標です。 本ドキュメントに記載されている、社名、商品名等は各社の商標または 登録商標である場合があります。 その他の記載されている、商標および登録商標については、 一般に各社の商標または登録商標です。

Slide 57

Slide 57 text

56 Copyright 2010 FUJITSU LIMITED