Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

コンピューティングとJava~なにわTECH道

1,202 views

Published on

2016/9/3 なにわTECH道

Published in: Software
  • Be the first to comment

コンピューティングとJava~なにわTECH道

  1. 1. これからの コンピューティングの変化と Java 2016/9/3 きしだ なおき
  2. 2. 自己紹介 ● 午前中に起きれるようになりました。
  3. 3. 今日の話 ● ハードウェアが変わっていく ● Javaも変わらないとね
  4. 4. 最近こんな経験ありますか? ● メモリやコア数は同じでいいけど速いCPUが 載ったマシンに買い換えよう
  5. 5. 最近こんな経験ありますか? ● サーバーが遅いからサーバーを増やそう
  6. 6. 最近こんな経験ありますか? ● サーバーが遅いからデータベースをメモリに キャッシュしよう
  7. 7. 処理を速くするには ● CPUを載せ換えたら勝手に速くなる時代は10 年前に終わった ● 並列度をあげる ● より近いところにデータを置く
  8. 8. ムーアの法則 ● 18ヶ月(or24ヶ月)でトランジスタの数が倍に なる ● 寸法半減→スピード2倍、消費電力1/4 https://en.wikipedia.org/wiki/Moore's_law
  9. 9. ムーアの法則の終焉 ● 物理的に配置できない – 5nm=水素原子50個分 ● 電子が漏洩する – 電気を余分に消耗する ● 歩留まりがあがらない – 製造コスト増
  10. 10. 微細化が進んでも今までとは違う ● コストが下がらない ● 低消費電力と高速化を同時に実現できない ● たくさん回路をつんでも、すべての回路に電気 を流せない – ダークシリコン問題
  11. 11. データ・セントリック・システム ● データの移動に電力や時間が食われている – ストレージ→メインメモリ→キャッシュメモリ ● データの移動を減らす必要がある ● データの近くで処理を行う ● 処理を行うのはCPUだけではなくなる ● いろいろなところで動くコードが必要になる
  12. 12. コンピュータの種類 ● ノイマン型アーキテクチャ ● 非ノイマン型アーキテクチャ
  13. 13. ノイマン型アーキテクチャ ● メモリから命令をよびだして、命令にしたがっ た回路で処理を行う ● CPU ● GPU
  14. 14. CPU ● 高機能・高性能・高粒度 ● 割り込み、権限制御、仮想化、など実行以外の機能 ● OSが実行できる ● 演算器はコアあたり10個程度 – 一チップに100個程度 ● 明示的にメモリを制御できない – いかにキャッシュに載せるか = いかにメモリをまとめて扱うか
  15. 15. GPU ● GPU – ちょうたくさんコアがある – 同じ処理を行う – 行列計算に向いてる ● GTX 1080 – 2560コア!
  16. 16. GPUの構成 ● いくつかのコアでグループを作る – 同時に同じ命令を実行する – グループだけからアクセスできるメモリをもつ ● コアのグループが多数ある ● コアあたり数個の演算器 – 数千から数万の演算器
  17. 17. 非ノイマン型アーキテクチャ ● ノイマン型じゃないコンピュータ全体 – FPGA – ニューラルネット型コンピュータ – 量子コンピュータ
  18. 18. FPGA ● Field Programmable Gate Array – Field 現場で – Programmable プログラム可能な – Gate 論理素子が – Array いっぱい並んだやつ ● 現場でプログラムできる論理回路
  19. 19. 回路の入出力の組み合わせ 入力 出力 000 0 100 0 010 0 110 1 001 1 101 1 011 1 111 1
  20. 20. LUT(LookUp Table) ● 入出力をあらかじめメモリにもっておく ● 製品としては4入力LUTや6入力LUT 入力 出力 000 0 100 0 010 0 110 1 001 1 101 1 011 1 111 1
  21. 21. 論理ブロック ● Logical Element(LE) Altera ● Logical Cell(LC) Xilinx
  22. 22. 配線 ● 論理ブロックが格子状に配置 ● 周囲に配線 ● アイランドスタイル
  23. 23. 乗算回路とメモリ ● 乗算やメモリを論理ブロックの組み合わせで 実現すると効率がわるい ● 乗算回路やメモリ(SRAM)がのってる – 演算器は数百から数千
  24. 24. FPGAの構成
  25. 25. FPGAなら ● 命令を読み込む必要なく、回路をやりたい処 理のとおり並べることができる
  26. 26. FPGAの利点 ● 命令を読み込む必要がない – 処理を行うまでのタイムラグが少ない ● 低レイテンシ – 命令解析のための回路が不要 ● 余分な回路がないので低消費電力 ● 細かな並列化
  27. 27. Javaでいろいろやってみる ● JavaでCPU(並列) ● JavaでGPU ● JavaでFPGA
  28. 28. JavaでCPU(並列) ● Java8 Stream int elementCount = 1_444_477; float[] inputA = new float[elementCount]; float[] inputB = new float[elementCount]; float[] output = new float[elementCount]; IntStream.range(0, elementCount).parallel().forEach(i -> { output[i] = inputA[i] * inputB[i]; });
  29. 29. JavaでGPU ● Aparapi – JavaコードをOpenCLに変換 ● OpenCLを呼び出す – OpenCL:並列計算フレームワーク ● AMD始め、IntelやNVIDIAなどが参加 – JOCL(jogamp.org) – JOCL(jocl.org) – JavaCL ● Project Sumatra – Stream処理を自動的にGPUで行う – Java VMに組み込む
  30. 30. Aparapi ● A PARalell API ● 実行時にJavaコードをOpenCLに変換 ● https://code.google.com/p/aparapi/
  31. 31. Aparapiコード public class AparapiKernel extends Kernel{ float[] inputA; float[] inputB; float[] output; @Override public void run() { int gid = getGlobalId(); output[gid] = inputA[gid] * inputB[gid]; } public static void main(String[] args) { AparapiKernel kernel = new AparapiKernel(); int elementCount = 1_444_477; kernel.inputA = new float[elementCount]; kernel.inputB = new float[elementCount]; kernel.output = new float[elementCount]; fillBuffer(kernel.inputA); fillBuffer(kernel.inputB); kernel.execute(elementCount); } }
  32. 32. JOCL(jogamp.org) ● OpenCLを薄くラップ ● https://jogamp.org/jocl/www/
  33. 33. JOCLのコード String KERNEL_CODE = "kernel void add(global const float* inputA," + " global const float* inputB," + " global float* output," + " uint numElements){" + " size_t gid = get_global_id(0);" + " if(gid >= numElements){" + " return;" + " }" + " output[gid] = inputA[gid] + inputB[gid];" + "}"; CLContext ctx = CLContext.create(); CLDevice device = ctx.getMaxFlopsDevice(); CLCommandQueue queue = device.createCommandQueue(); CLProgram program = ctx.createProgram(KERNEL_CODE).build(); int elementCount = 1_444_477; int localWorkSize = Math.min(device.getMaxWorkGroupSize(), 256); int globalWorkSize = ((elementCount + localWorkSize - 1) / localWorkSize) * localWorkSize; CLBuffer<FloatBuffer> clBufferA = ctx.createFloatBuffer( elementCount, CLMemory.Mem.READ_ONLY); CLBuffer<FloatBuffer> clBufferB = ctx.createFloatBuffer( elementCount, CLMemory.Mem.READ_ONLY); CLBuffer<FloatBuffer> clBufferC = ctx.createFloatBuffer( elementCount, CLMemory.Mem.READ_WRITE); fillBuffer(clBufferA.getBuffer()); fillBuffer(clBufferB.getBuffer()); CLKernel kernel = program.createCLKernel("add"); kernel .putArgs(clBufferA, clBufferB, clBufferC) .putArg(elementCount); queue.putWriteBuffer(clBufferA, false) .putWriteBuffer(clBufferB, false) .put1DRangeKernel(kernel, 0, globalWorkSize, localWorkSize) .putReadBuffer(clBufferC, true);
  34. 34. 比較 ● Aparapi – めちゃ楽 – GPUの性能出しにくい ● JOCL – ちょっと面倒 – GPUの性能出しやすい
  35. 35. ところでディープラーニング 実装してみました ※正しく動くようになったとは言ってない
  36. 36. ディープラーニング(深層学習) ● 階層の深いニューラルネット ● 最近、人工知能っていわれてるのは、ほぼこれ ● 学習には大量のデータを処理する必要がある
  37. 37. CPUを使って処理 ● AlexNet – 画像認識用ディープニューラルネット – それまでの画像認識とは段違いの識別能力 – ディープラーニングを一躍有名に ● 学習には1400万枚の画像を読み込ませる必要がある。 ● 普通にJavaで記述 ● 処理能力:15枚/分 – 1400万枚だと600日!
  38. 38. Aparapiを使う ● JavaのコードをそのままGPU対応 ● 15枚/分→90枚/分 ● 1400万枚の画像処理が600日→100日!
  39. 39. JOCLを使う ● 90枚/分→298枚/分 ● 1400万枚の画像処理が100日→34日!
  40. 40. なんでこんなに速くなったか ● Aparapi版 – 各層の処理前にCPUからGPUにデータを転送 – 処理後に結果をGPUからCPUに転送 ● JOCL版 – 処理前に転送するデータは、前の層の結果 – そのままGPUに置きっぱなしにする
  41. 41. つまり ● 100日→34日 ● 66日短縮 ● 66日間はデータ転送だけだった
  42. 42. GPUローカルメモリを使う ● 298枚/分→300枚/分 ● 1400万枚の画像処理が34日→33日 ● 1日データ転送をしていた
  43. 43. GPUでの結果 ● 90枚/分→300枚/分 ● 1400万枚の画像処理が100日→33日 ● 67日はデータの移動だけに電気代を払うこと になっていた!
  44. 44. FPGAでやったら? ● Microsoftの実装 – GPUの半分のスループット – 1/10の消費電力 – 電力あたりの性能は3倍 – http://techon.nikkeibp.co.jp/article/MAG/20150311/408682/
  45. 45. ASICで作ったら? ● Google TensorFlow Processing Unit ● 碁で人間より強くなる
  46. 46. Sumatra ● Java VMに組み込むことを目標 ● 実装難しそう ● コード書くのもわかりにくそう ● 性能出しにくそう ● Java VMに組み込むほどメリットなさそう – 性能欲しい人はOpenCL使うよね
  47. 47. と思ったら ● 「Sumatra is not in active development for now.(2015/5/1) 」 http://mail.openjdk.java.net/pipermail/sumatra-dev/2015-May/000310.html
  48. 48. JavaでFPGA ● Synthesijer – JavaコードからVHDL/VerirogHDLを生成
  49. 49. Synthesijer ● みよしさんが作ってるオープンソース http://synthesijer.github.io/web/ public class Test { public boolean flag; private int count; public void run(){ while(true){ count++; if(count > 5_000_000){ count = 0; flag = !flag; } } } } @synthesijerhdl public class Top { private final Test test = new Test(); @auto public boolean flag(){ return test.flag; } @auto public void main(){ test.run(); } }
  50. 50. Synthesijerが出力したコード module Test ( input clk, input reset, input flag_in, input flag_we, output flag_out, output run_busy, input run_req ); wire clk_sig; wire reset_sig; wire flag_in_sig; wire flag_we_sig; wire flag_out_sig; reg run_busy_sig = 1'b1; wire run_req_sig; reg class_flag_0000 = 1'b0; wire class_flag_0000_mux; wire tmp_0001; reg signed [32-1 : 0] class_count_0001 = 0; reg signed [32-1 : 0] unary_expr_00005 = 0; reg binary_expr_00007 = 1'b0; reg unary_expr_00011 = 1'b0; wire run_req_flag; reg run_req_local = 1'b0; wire tmp_0002; localparam run_method_IDLE = 32'd0; localparam run_method_S_0000 = 32'd1; localparam run_method_S_0001 = 32'd2; localparam run_method_S_0002 = 32'd3; localparam run_method_S_0003 = 32'd4; localparam run_method_S_0004 = 32'd5; すごく長い
  51. 51. Javaでもいろいろできる でも今のままで足りるの?
  52. 52. 足りない ● Javaの基本ライブラリが大きすぎる(そしてほとんど使わない) ● オブジェクトのメモリ効率が悪い ● さまざまなアーキテクチャに対応した値が扱えない – 256bit整数型、float x 4型(SIMD命令用) ● 高機能データ構造がメモリにやさしくない – Genericsが基本型を扱えない ● 配列がハードウェアにやさしくない – 多次元配列 – 21億(int上限)を超える要素 – 読み込み専用配列
  53. 53. Java 9 ● 来年春リリース予定 ● モジュールシステム(Jigsaw) ● GCアルゴリズムのデフォルトがG1GCに ● JShell
  54. 54. モジュールシステム ● いままでの可視性制御 – public, package private, private – public見えすぎ問題 ● これからの可視性制御 – module export, public, package private, private ● Java自体のモジュール化 – フットプリントの最適化
  55. 55. G1GC ● いままでのメモリ領域 – New(Eden/Survivor), Tenuredが固定 ● G1GC – メモリを多数のブロックにわけて、動的にNew領 域、Tenured領域に割り当てる
  56. 56. JShell ● REPL ● 便利
  57. 57. Java9の先
  58. 58. Close To the Metal
  59. 59. Valhallaへの道
  60. 60. Project Valhalla ● Value Type ● Specialization
  61. 61. Value Type ● ユーザー定義基本型 ● Codes like a class, works like an int!
  62. 62. Pointクラス class Point{ final int x; final int y; }
  63. 63. Pointクラスの配列
  64. 64. Pointクラスの配列の効率化
  65. 65. ValueType版Point value class Point{ final int x; final int y; }
  66. 66. ValueType版Pointの配列
  67. 67. Specialization ArrayList<int>
  68. 68. Java8の美しくないクラス ● StreamとIntStream – IntStream extends Stream<int>ってやりたい – そもそも捨てたい ● OptionalとOptionalInt – OptionalInt extends Optional<int>ってやりたい – そもそも捨てたい
  69. 69. ValueType対応 ● それぞれのValueTypeにあわせたコレクショ ンを作るのは無理
  70. 70. Genericなクラス class Box<T>{ T value; Box(T v){ value = v; } T getValue(){ return T; } }
  71. 71. 現在のコンパイル結果 class Box{ Object value; Box(Object v){ value = v; } Object getValue(){ return value; } }
  72. 72. Specialize可能なクラス class Box<any T>{ T value; Box(T v){ value = v; } T getValue(){ return value; } }
  73. 73. Specialize対応のコンパイル結果 class Box{ Object*T value; Box(Object*T v){ value = v; } Object*T getValue(){ return value; } }
  74. 74. Box<int>の場合 class Box${T=int}{ int value; Box(int v){ value = v; } int getValue(){ return value; } }
  75. 75. Name Mangling ● 名前修飾 ● Javaの入れ子クラス – Hoge$Foo ● Specializedなクラス – Box${T=I}
  76. 76. Java VMはどうするか
  77. 77. Javaのバイトコード ● aload/iload/lload/fload/dload ● astore/istore/lstore/fstore/dstore ● areturn/ireturn/lreturn/freturn/dreturn
  78. 78. 演算のバイトコード ● iadd/isub/imul/idiv ● ladd/lsub/lmul/ldiv ● dadd/dsub/dmul/ddiv ● fadd/fsub/fmul/fdiv
  79. 79. バイトコードの統一 ● 型をもったまま汎用の構文 ● 新しい型を自然に拡張できる ● vload/vstore/vreturn ● vadd/vsub/vmul/vdiv
  80. 80. 既存コードは省略形 ● iload → vload :I ● daload → vaload :D – さらにinvokeinterface Array.getElementの略に できるかも!
  81. 81. バイトコードレベルの Specialization不要
  82. 82. まとめ ● コンピュータは変わる ● Javaも変わる ● あんたはどうだい?

×