Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Slides2.pdf

 Slides2.pdf

Avatar for Vladimir Makarov

Vladimir Makarov

June 02, 2018

More Decks by Vladimir Makarov

Other Decks in Programming

Transcript

  1. Three CRuby Performance Projects Vladimir Makarov Red Hat June 2nd,

    2018 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 1 / 38
  2. Three CRuby Performance Projects Vladimir Makarov Red Hat June 2nd,

    2018 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 2 / 38
  3. About Myself Red Hat, Toronto office, Canada Tools group (GCC,

    GLIBC, LLVM, Rust, OpenMP, ...) a part of bigger platform enablement team (porting Linux kernel to new hardware) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 3 / 38
  4. About Myself Red Hat, Toronto office, Canada Tools group (GCC,

    GLIBC, LLVM, Rust, OpenMP, ...) a part of bigger platform enablement team (porting Linux kernel to new hardware) almost 40 years of work on different programming language implementations Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 3 / 38
  5. About Myself Red Hat, Toronto office, Canada Tools group (GCC,

    GLIBC, LLVM, Rust, OpenMP, ...) a part of bigger platform enablement team (porting Linux kernel to new hardware) almost 40 years of work on different programming language implementations 20 years of work on GCC Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 3 / 38
  6. About Myself Red Hat, Toronto office, Canada Tools group (GCC,

    GLIBC, LLVM, Rust, OpenMP, ...) a part of bigger platform enablement team (porting Linux kernel to new hardware) almost 40 years of work on different programming language implementations 20 years of work on GCC 2.5 years of work on CRuby Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 3 / 38
  7. Presentation Outline 1 Improving CRuby floating point peformance Vladimir Makarov

    (Red Hat) Three CRuby Performance Projects June 2nd, 2018 4 / 38
  8. Presentation Outline 1 Improving CRuby floating point peformance 2 Update

    on RTL for CRuby Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 4 / 38
  9. Presentation Outline 1 Improving CRuby floating point peformance 2 Update

    on RTL for CRuby 3 Light-weight JIT for CRuby and MRuby Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 4 / 38
  10. 1. Improving CRuby FP Performance CRuby FP is very slow

    Interpretation is not the only reason ... Floating point number representation is the biggest factor! Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 5 / 38
  11. CRuby value representation 0 0 0 Pointer to the heap

    61 bits 3 bits CRuby uses tagged values Pointers to heap objects have tag 000 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 6 / 38
  12. CRuby value representation 0 0 0 Pointer to the heap

    61 bits 3 bits 1 63 bits Fixnum CRuby uses tagged values Pointers to heap objects have tag 000 Fixnum values use 63 bits and have tag 1 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 6 / 38
  13. CRuby value representation 0 0 0 Pointer to the heap

    61 bits 3 bits 1 63 bits Fixnum 1 0 62 bits FP number CRuby uses tagged values Pointers to heap objects have tag 000 FP values use 62 bits and have tag 01 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 6 / 38
  14. IEEE double Fraction Exponent 52 bits 11 bits Sign The

    exponent value is biased (add 1023) The non-biased exponent value is in range -1023..1024 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 7 / 38
  15. Placing IEEE doubles into 62 bits Fraction Exponent 52 bits

    11 bits Sign Put doubles with some fixed values of some 2 bits in value Put other doubles into the heap Fixing sign or fraction bits is a bad idea ∼ 3/4 of all doubles will be in the heap Fixing exponent bits is the only reasonable choice Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 8 / 38
  16. The current placing double into value S xyz ... Sxy

    z Rotate left by 3 bits S10 z Change xy by FP tag 10 Fixed bit values xyz 100 011 z defines possible xyz combination in reverse transformation Doubles with exponent in range [-255, +256] are put into the value Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 9 / 38
  17. The current transformation code union { double d; VALUE v;

    } t; int bits; t.d = d; bits = (int)((VALUE)(t.v >> 60) & 0x7); if (t.v != 0x3000000000000000 /* 1.72723e-77 */ && !((bits-3) & ~0x01)) { return (RUBY_BIT_ROTL(t.v, 3) & ~(VALUE)0x01) | 0x02; } else if (t.v == (VALUE)0) { /* +0.0 */ return 0x8000000000000002; } /* else create heap representation */ Most of the code checks values of the fixed bits Using 2 most significant exponent bits for the tag Special case: +0.0 replaces rarely used value 1.72723e-77 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 10 / 38
  18. What is wrong with the code? Too many branches Branches

    are expensive Might be even more expensive after mitigating speculative execution vulnerabilities (Spectre) Prevents optimizations in JIT Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 11 / 38
  19. Proposed placing double into value S wxyz ... Swxyz Rotate

    left by 5 bits Suv10 XOR wxyz and mask Fixed bit values wxyz mask uv10 0000 0010 0010 0111 0001 0110 1000 0010 1010 1001 0111 1110 uv defines wxyz in reverse transformation The same number of doubles are put into the values But exponent should be in ranges [-1023, -996] and [-127, +256] Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 12 / 38
  20. The proposed transformation code union double d; VALUE v; t;

    unsigned int sh; VALUE m; const VALUE c = 0x7210000002; /* the table */ t.d = d; v = RUBY_BIT_ROTL(t.v, 5); sh = (v & 0xf) << 2; m = (c >> sh) & 0xf; if (LIKELY (m != 0)) return v ^ m; /* create heap representation: */ Only one branch ... instead of three branches in current CRuby code. Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 13 / 38
  21. Performance results Intel i3-7100 under FC25 with GCC-6.3 bench.rb (image

    manipulations) with heavy FP use Base FP New FP Base-MJIT New-MJIT JRuby9k Graal-0.31 0.0 0.5 1.0 1.5 2.0 2.5 3.0 Speedup 1.45 1.04 2.98 1.12 1.72 Wall time Speedup Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 14 / 38
  22. 2. RTL Update Stack insns simple, stable, and small number

    of them (100 insns) better as an interface language RTL insns unstable and complicated insn set (a bit less 400 insns) better for interpretation, optimizations, and JITting Generating RTL insns from stack insns, not from abstract nodes Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 15 / 38
  23. Stack insns to Unoptimized RTL getlocal var getlocal incr getlocal

    var putobject 10 opt_plus Stack Insns var2temp t1, var var2temp t2, incr var2temp t1, var val2temp t2, 10 plus t1, t1, t2 Unoptimized RTL Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 16 / 38
  24. Stack insns to Optimized RTL getlocal var getlocal incr getlocal

    var putobject 10 opt_plus Stack Insns var2temp t2, incr val2temp t2, 10 plus t1, var, t2 Optimized RTL Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 17 / 38
  25. Optimized RTL Data Flow Problem Unknown Value 1 ... Local

    1 ... String 1 ... Temp Temp Lattice for one stack slot Forward Data Flow Problem: Stack InBB = P∈Pred(BB) Stack OutP Stack OutBB = (Stack InBB ∩¬Stack KillBB )∪Stack GenBB Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 18 / 38
  26. RTL vs Stack Insns: Interpr. Performance aread aref aset awrite

    bench call cmbrot const const2 fannk fib ivread ivwrite mbrot meteor nbody ntimes nwhile norm nsvb pent sieve trees while GEOMEAN 0.0 0.5 1.0 1.5 2.0 2.5 Speedup 1.65 2.26 2.41 1.60 1.18 1.34 1.11 1.81 1.85 1.06 1.25 1.29 1.99 1.30 1.06 1.16 1.19 1.88 1.10 1.08 1.23 1.50 1.09 2.10 1.43 Stack insns vs RTL: Interpreter Speedup Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 19 / 38
  27. RTL vs Stack Insns: MJIT Performance aread aref aset awrite

    bench call cmbrot const const2 fannk fib ivread ivwrite mbrot meteor nbody ntimes nwhile norm nsvb pent sieve trees while GEOMEAN 0 1 2 3 4 5 6 7 Speedup 5.94 4.74 5.88 4.03 1.50 1.14 1.20 3.02 3.03 1.06 1.37 1.75 2.53 1.44 1.26 1.74 1.98 1.91 1.48 1.08 1.24 1.23 1.37 3.52 1.97 Stack insns vs RTL: JIT Code Speedup Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 20 / 38
  28. RTL vs Stack Insns: OptCarrot optcarrot optcarrot --opt optcarrot (JIT)

    optcarrot --opt (JIT) 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 Speedup 0.96 1.27 1.17 1.23 Stack insns vs RTL: OptCarrot Speedup (2000 frames) Generation of RTL adds only 0.5-1% to compilation time of OptCarrot benchmark Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 21 / 38
  29. 3. Light-Weight JIT MJIT feedback: “I don’t want a C

    compiler in my production environement” In some environments MJIT using C compilers is still slow: MinGW, Windows non-standard environments prohibiting in-memory FS usage MJIT memory footprint is smaller than JRuby and Graal one but still can be big for cloud applications Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 22 / 38
  30. 3. Light-Weight JIT One possible solution is a light-weight JIT

    in addition to existing MJIT: The light-weight JIT as tier 1 JIT compiler Existing MJIT generating C as tier 2 JIT compiler for more frequently running code Or only the light-weight JIT for environments where MJIT does not work Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 22 / 38
  31. Mobile and IoT Market Rakuten KOBO Glo Ebook Reader: 800MHz

    ARM Cortex-A8, Freescale MX50, 256MB memory, ∼50 slower than Intel i3-7100 A good piece of hardware PDF support is not good People use alternative PDF Reader KoReader KoReader is writen on LuaJIT Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  32. Mobile and IoT Market Can KoReader be implemented with Ruby?

    Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  33. Mobile and IoT Market Can KoReader be implemented with Ruby?

    CRuby is big and slow Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  34. Mobile and IoT Market Can KoReader be implemented with Ruby?

    CRuby with MJIT, JRuby, Graal Ruby are even bigger. Long warmup of the JITs: 30ms method compilation on Intel CPU means 1.5s on Frescale MX50 Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  35. Mobile and IoT Market Can KoReader be implemented with Ruby?

    MRuby is too slow Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  36. Mobile and IoT Market MRuby with a light weight JIT

    could be a solution MRuby with a light weight JIT could expand mobile market for Ruby Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 23 / 38
  37. Light-Weight JIT My spare-time project started this year: Universal light-weight

    JIT based on MIR Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 24 / 38
  38. Light-Weight JIT My spare-time project started this year: Universal light-weight

    JIT based on MIR MIR is Medium Internal Representation MIR means peace and world in Russian MIR is strongly typed MIR can represent machine insns of different architectures Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 24 / 38
  39. Light-Weight JIT My spare-time project started this year: Universal light-weight

    JIT based on MIR MIR is Medium Internal Representation MIR means peace and world in Russian MIR is strongly typed MIR can represent machine insns of different architectures Plans to try the light-weight JIT first for CRuby or/and MRuby Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 24 / 38
  40. Example: C Prime Sieve #define Size 819000 int sieve (void)

    { int i, k, prime, count, n; char flags[Size]; for (n = 0; n < 1000; n++) { count = 0; for (i = 0; i < Size; i++) flags[i] = 1; for (i = 0; i < Size; i++) if (flags[i]) { prime = i + i + 3; for (k = i + prime; k < Size; k += prime) flags[k] = 0; count++; } } return count; } Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 25 / 38
  41. Example: MIR Prime Sieve sieve: func 819000, 0, 7, i64:flags,

    i64:count, i64:prime, \ i64:n, i64:i, i64:k, i64:temp mov flags, fp; mov n, 0 loop: bge fin, n, 1000 mov count, 0; mov i, 0 loop2: bgt fin2, i, 819000 mov ui8:(flags, i), 1; add i, i, 1; jmp loop2 fin2: mov i, 0 loop3: bgt fin3, i, 819000 beq cont3, ui8:(flags,i), 0 add temp, i, i; add prime, temp, 3; add k, i, prime loop4: bgt fin4, k, 819000 mov ui8:(flags, k), 0; add k, k, prime; jmp loop4 fin4: add count, count, 1 cont3: add i, i, 1; jmp loop3 fin3: add n, n, 1; jmp loop fin: ret count endfunc Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 26 / 38
  42. Light-Weight JIT Performance Goals Comparing to GCC -O2 70% of

    generated code speed 100 times faster compilation speed 100 times faster start-up 100 times smaler code size less 10K C LOC Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 27 / 38
  43. How to achieve the performance goals? Use few most valuable

    optimizations Optimize only frequent cases Use Algorithms with best combination of simplicity (code size) and performance Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 28 / 38
  44. How to achieve the performance goals? What are the most

    valuable GCC optimizations for x86-64? Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 28 / 38
  45. How to achieve the performance goals? What are the most

    valuable GCC optimizations for x86-64? a decent RA code selection GCC -O2 GCC -O0 + fast RA + combiner SPECInt2000 4627 3641 (79%) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 28 / 38
  46. Optimizing compiler performance reality Moore’s “law” (ICs): number of transistors

    doubles every 18 months Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 29 / 38
  47. Optimizing compiler performance reality Moore’s “law” (ICs): number of transistors

    doubles every 18 months Proebsting’s “law” (optimizing compilers): compiler advances double computing power every 18 Years Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 29 / 38
  48. Optimizing compiler performance reality Proebsting’s “law” is too optimistic: GCC

    3.1 (the first version supporting x86-64) was released 16 years ago GCC 8.0 was released recently Peak performance on 4.2GHz i7-4790K: GCC-3.1 (-O3), GCC-8 (-Ofast -flto -march=native) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 29 / 38
  49. Optimizing compiler performance reality Proebsting’s “law” is too optimistic: GCC

    3.1 (the first version supporting x86-64) was released 16 years ago GCC 8.0 was released recently Peak performance on 4.2GHz i7-4790K: GCC-3.1 (-O3), GCC-8 (-Ofast -flto -march=native) GCC 3.1 GCC 8 SPECInt2000 w/o eon 4498 5212 (+16%) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 29 / 38
  50. Optimizing compiler performance reality Extreme point of view (Dr. Bernstein,

    “The death of optimizing compilers”): No needs for optimizing compilers Another point of view: Computers consumed 10% of world electricity (a 2013 estimation) Link 1% performance improvement for energy proportional computing (an IT goal) means saving 20TWh annualy Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 30 / 38
  51. Optimizing compiler performance reality 20TWh is an annual production of

    5 Hoover dams Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 31 / 38
  52. The current state of MIR project MIR API MIR text

    x86-64 MIR text Interpreter Generator Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 32 / 38
  53. Possible future directions of MIR project MIR API C LLVM

    IR WASM C++ Rust MIR binary MIR text C x86-64 aarch64 PPC64 MIPS64 MIR binary MIR text ... Interpreter Generator Java bytecode Java bytecode ... Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 33 / 38
  54. MIR Generator Simplify Machinize Build CFG MIR Simplify: Lowering MIR

    Machinize: Machine-dependent code transforming MIR for calls ABI, 2-op insns, etc Build CFG: Building Control Flow Graph (basic blocks and CFG edges) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 34 / 38
  55. MIR Generator Simplify Machinize Build CFG Build Live Info Build

    Live Ranges Assign Registers Rewrite MIR Building Live Info: Calculating live in and live out for the basic blocks Build Live Ranges: Calculating program point ranges for registers Assign: Priority-based RA Rewrite: Transform MIR according to RA assignments Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 34 / 38
  56. MIR Generator Simplify Machinize Build CFG Build Live Info Build

    Live Ranges Assign Registers Rewrite Combine Insns Dead Code Elimination Generate Machine Code MIR Machine Code Combine (code selection): Merging data-dependent insns into one Dead code elimination: Removing insns with unused outputs Generate machine insns: Machine-dependent code creating machine insns Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 34 / 38
  57. Current Performance Results Intel i3-7100 under FC25 with GCC-6.3 MIR-gen

    MIR-interp gcc -O2 gcc -O0 compilation 1.0 (0.05ms) 0.2 (0.01ms) 560 (28ms) 440 (22ms) execution 1.0 (3.51s) 6.7 (23.42s) 0.99 (3.48s) 2.3 (7.96s) Table: Sieve: MIR vs GCC Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 35 / 38
  58. Current Performance Results Intel i3-7100 under FC25 with GCC-6.3 JIT

    based on MIR-gen MIR-interp gcc -O21 gcc -O01 initialization 1.0 (0.08ms) 1.0 (0.08ms) 630 (50ms) 910 (73ms) code size 1.0 (71KB) 0.61 (43KB) 352 (25MB) 352 (25MB) C LOC 1.0 (2+2+1K2) 0.4 (2K) 0.24 (1.2K) 0.24 (1.2K) Table: MIR vs GCC based JIT: estimation based on Sieve 1GCC data are based on CRuby RTL MJIT. C LOC is for RTL to C translator only 21K C LOC is x86-64 dependent code, 2K - MIR API and aux. data structure code (hashtabs, bitmaps, etc) Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 35 / 38
  59. Current MJIT Environment header Minimized header CRuby building phase MJIT

    CRuby execution run CRuby Precompiled header C code .so file CC CC loading Generated Machine code Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 36 / 38
  60. MIR as tier1 compiler in MJIT Environment header Minimized header

    CRuby building phase MJIT CRuby execution run CRuby Precompiled header C code .so file CC CC loading MIR binaries MIR Generator API Generated Machine code C-to-MIR Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 37 / 38
  61. MIR Short Term Plans Implement C to MIR translator Try

    MIR Generator in CRuby MJIT or/and in MRuby Implement function inlining Implement AARCH64 MIR Generator Vladimir Makarov (Red Hat) Three CRuby Performance Projects June 2nd, 2018 38 / 38