• 検索結果がありません。

JS2-14 マルチコアCPU時代の Javaプログラミング

N/A
N/A
Protected

Academic year: 2021

シェア "JS2-14 マルチコアCPU時代の Javaプログラミング"

Copied!
30
0
0

読み込み中.... (全文を見る)

全文

(1)

JS2-14

マルチコアCPU時代の

Javaプログラミング

2012年4月5日

富士通株式会社

数村 憲治

JavaOne Tokyo 2012

(2)

数村 憲治 [email protected]

富士通株式会社

Interstage Application Server開発チーム

Java VMの開発・サポート

大規模システムでの性能チューニングに、

数多く携わる

(3)

ハードウェアの進化と性能問題

メモリ関連問題

ロック関連問題

まとめ

Q&A

アジェンダ

(4)

ハードウェアの進化と性能問題

いまどきのCPU

コア数を意識するJava

よくあるパターン

メモリ関連問題

ロック関連問題

まとめ

Q&A

アジェンダ

(5)

いまどきのCPU

Xeon E7-8870 コア数10 スレッド数 20 SPARC T3 コア数16 スレッド数128 PRIMEQUEST 1800E2 CPU数 8 コア数 80 スレッド数 160 SPARC T3-4 CPU数 4 コア数 64 スレッド数 512

マルチコアからメニーコアへ

(6)

HotSpot VMのエルゴノミクス機能

Java VMが動作するマシン情報から自動判定

GCのワーカースレッド数に影響

コア数を意識するJava

-XX:ParallelGCThreads=n (パラレルGC使用時) -XX:ConcGCThreads=n (コンカレントGC使用時)

"GC task thread#0 (ParallelGC)" prio=10 tid=0x088d1800 nid=0x3428 runnable "GC task thread#1 (ParallelGC)" prio=10 tid=0x088d3000 nid=0x3429 runnable "GC task thread#2 (ParallelGC)" prio=10 tid=0x088d4400 nid=0x3430 runnable "GC task thread#3 (ParallelGC)" prio=10 tid=0x088d5000 nid=0x3431 runnable "GC task thread#4 (ParallelGC)" prio=10 tid=0x088d6000 nid=0x3432 runnable ・・・・

(7)

java.util. concurrent.ForkJoinPool

タスクを分割し、work-stealingモデルで並列に実行。

デフォルトの並列数は、論理CPU数。

コア数を意識するJava

ForkJoinPool pool = new ForkJoinPool(); pool.invoke(someTask);

ForkJoinPool pool = new ForkJoinPool(properValue); pool.invoke(someTask);

(8)

よくあるパターン

CPUのマルチコア・スレッド化により論理CPU数の増加

ハードの性能が上がった、と喜ぶ

アプリケーションで同時に実行するスレッド数を増加させる

(9)

ハードウェアの進化と性能問題

メモリ関連問題

メモリアロケーション

ガベージコレクション

ロック関連問題

まとめ

Q&A

アジェンダ

(10)

Javaのアロケーションはロックレス

TLAB(Thread Local Alloc Buffer)

メモリアロケーション

Eden領域(初期状態) スレッドAに割当て スレッドBに割当て スレッドAからの メモリ要求 スレッドBからの メモリ要求 Eden領域(アロケート時) 多重度を上げても問題ないように見えるが。。。

(11)

スレッド数が多いとTLABが非効率に

メモリアロケーション

Eden領域 スレッド1用 スレッド2用 スレッド4用 スレッド3用 スレッド5用 スレッドN用 使用域 未使用域 スレッド(N+1)用のTLABが 割当てられない Eden全体では、 未使用域がたくさんあるが、 GCが発生

(12)

JNI使用時には注意が必要

ガベージコレクション

cstr = (*env)->GetStringCritical(env, string, &isCopy); 長い処理 ~ (*env)->ReleaseStringCritical(env, string, cstr); GetStringCritical  ReleaseStringCritical間は、 ガベージコレクションが抑止。 他のスレッドでOutOfMemoryErrorの可能性。 GetPrimitiveArrayCriticalも同様。

(13)

ハードウェアの進化と性能問題

メモリ関連問題

ロック関連問題

JavaVMロック機構の進化

無意識のロック

フェアネスロック

性能分析

まとめ

Q&A

アジェンダ

(14)

JavaVMロック機構の進化

・OSのmutex関数を使用 ・オブジェクト毎にmutexを用意 ・ロード命令を 使用 ロック機構の進化はロック競合時の改良ではない ・CAS命令を使用 ・マルチコアCPUでは CASのコストが増大 ほとんどのロックは 競合していない ほとんどのロックは 共有すらされていない 第一世代 ヘビーロック 第二世代 シンロック 第三世代 バイアスロック

(15)

APIドキュメントには、どのメソッドが

synchronizeメソッドか、記述なし

内部的にsynchronizedブロックを使用している

場合もあり

無意識のロック

java.util.Hashtable

java.lang.StringBuffer

java.lang.String#getBytes()

java.net.InetAddress#getAllByName()

java.io.File#renameTo()

・・・

(16)

java.util.Hashtableクラス

ほとんどのメソッドがsynchronizeメソッド

スレッドローカルで使用するなら、

java.util.HashMap等を。

java.lang.StringBufferクラス

ほとんどのメソッドがsynchronizeメソッド

java.lang.StringBuilderの使用を。

無意識のロック

(17)

java.lang.String#getBytes()

無意識のロック

at sun.nio.cs.FastCharsetProvider.charsetForName(FastCharsetProvi -waiting to lock <0x74b1e5d8> (a sun.nio.cs.StandardCharsets)

at java.nio.charset.Charset.lookup2(Charset.java:487) at java.nio.charset.Charset.lookup(Charset.java:475) at java.nio.charset.Charset.isSupported(Charset.java:517) at java.lang.StringCoding.lookupCharset(StringCoding.java:99) at java.lang.StringCoding.encode(StringCoding.java:335) at java.lang.String.getBytes(String.java:955) byte[] b1 = str1.getBytes(“MS932”); byte[] b2 = str2.getBytes(“EUC_JP”); byte[] b3 = str3.getBytes(“UTF-8”);

(18)

java.net.InetAddress#getAllByName()

無意識のロック

at java.net.InetAddress.getCachedAddresses(InetAddress.java:839) -waiting to lock <0x74b40e78> (a java.net.InetAddress$Cache)

at java.net.InetAddress.getAllByName0(InetAddress.java:1207) at java.net.InetAddress.getAllByName(InetAddress.java:1127) at java.net.InetAddress.getAllByName(InetAddress.java:1063)

(19)

java.io.File#renameTo()

(delete/mkdirs/getCanonicalPathも同様)

無意識のロック

at java.io.ExpiringCache.clear(ExpiringCache.java:98) -locked <0x9fa0c328> (a java.io.ExpiringCache)

at java.io.UnixFileSystem.rename(UnixFileSystem.java:276) at java.io.File.renameTo(File.java:1314)

File f1 = new File(“・・・”); File f2 = new File(“・・・”); f1.renameTo(f2);

(20)

フェアネスロック

lock = new Object();

・・・

public void run() {

for (int i = 0 ; i < 100 ; i++) { synchronized (lock) {

System.out.println(“i=" + i + " tid=" + Thread.currentThread().getId()); } } i=0 tid=9 i=1 tid=9 i=2 tid=9 i=3 tid=9 i=4 tid=9 i=5 tid=9 i=6 tid=9 ・・・ i=0 tid=9 i=0 tid=12 i=0 tid=11 i=1 tid=9 i=0 tid=10 i=0 tid=14 i=1 tid=10 ・・・ 期待する結果 実際の結果

(21)

フェアネスロック

スループット重視 ロック解放 ロック解放 ロック解放 ロック解放 レスポンス重視 ロック解放 ロック解放 ロック解放 ロック解放 ロック待ち ロック中 スレッドA スレッドB スレッドC スレッドD スレッドA スレッドB スレッドC スレッドD 各スレッドで ロック待ち時間が均等 飛びぬけて ロック待ち時間の長い スレッドが存在

(22)

モニター

待合室 オーナー部屋 Monitor Exit Monitor Entered Monitor Enter 待ちスレッド オーナースレッド 1: Monitor Enter: 待合室に入る。この段階ではロックは取れていない。 synchronized (o) { ・・・ 2: Monitor Entered: オーナー部屋に入る。この段階でロック獲得。 3: Monitor Exit: 部屋から退出。ロックを解放。 1 2 3

(23)

synchronize(d)は、フェアネスロックではない

フェアネスロック

lock = new ReentrantLock(true); // true:フェアネスの指定 ・・・

public void run() {

for (int i = 0 ; i < 100 ; i++) { try {

lock.lock();

System.out.println(“i=" + i + " tid=" + Thread.currentThread().getId()); } finally { lock.unlock(); }

}

フェアネスを期待する場合は、

(24)

System.out#println()による区間分析

性能分析

long time1 = System.currentTimeMillis();

System.out.println(“区間A開始:” + threadId + “:” + time1); n = n+1;

long time2 = System.currentTimeMillis();

System.out.println(“区間A終了:” + threadId + “:” + time2);

区間A開始:9:11000 区間A開始:8:11010 区間A終了:8:11020 ・・・ 区間A開始:7:20010 区間A終了:7:20020 区間A終了:9:21000 実行結果 スレッド9だけ、 10秒かかっている System.out#pintln()内でも synchronizedの使用

(25)

JVMTIの例

性能分析

void JNICALL cbMethodEnter(jvmtiEnv *env, …) { メソッド名の抽出

(*env)->RawMonitorEnter(…); メソッド名のログ書き込み

(*env)->RawMonitorExit(…);

void JNICALL cbMethodEnter(jvmtiEnv *env, …) { メソッド名の抽出

(*env)->GetThreadLocalStorage(env, thread, &tls); tlsへメソッド名の記録

(26)

ハードウェアの進化と性能問題

メモリ関連問題

ロック関連問題

まとめ

Q&A

アジェンダ

(27)

ハードウェアの更改時は要注意

プログラム変更が必要な場合も

わずかのロックが命取りに

できるだけロックを使わない

無意識に使っているロックを見極める

ロックポリシーの選択

レスポンス重視かスループット重視か

デバッグコードが性能ネックに

正しい性能測定を

まとめ

(28)
(29)
(30)

参照

関連したドキュメント

If DISB# and VCC are ready, but the voltage across the boot capacitor voltage is lower than 3.1 V, NCP303160 ignores the PWM input signal and starts the boot refresh circuit. The

In Default Interrupt mode, exceeding HTHL causes an interrupt that remains active indefinitely until reset by reading Interrupt Status Register 1 at address 01h or cleared by

The CS/ZCD multi-functional pin is designed to monitor the primary peak current for protection and light control and the auxiliary winding voltage for zero current detection..

&lt;7:3&gt; Remote 1 Temp T MIN R/W Contains the minimum temperature value for automatic fan speed control based on local temperature readings. T MIN can be programmed to

Because neither the operating point minus the hysteresis temperature nor the low temperature limit has been exceeded, the T MIN value is not adjusted, and the fan runs at a

♦ Smart Sense Mode allows some digital and analog peripherals to remain active to monitor and acquire data from external sensors at a very low system−level power consumption..

Courtesy: Monitor Gallery; Grimm, Amsterdam; Luhring Augustine, New

7 I pk Sense Peak Current Sense Input to monitor the voltage drop across an external resistor to limit the peak current through the circuit..