ݺߣ

ݺߣShare a Scribd company logo
Artur Skowroński
Digging for Truffles
Unveiling the Mysteries of GraalVM's Least Understood
Component
Artur Skowronski
Head of Java / Kotlin Development
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
GraalVM
GraalVM
GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
GraalVM
GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
🙇
165 ݺߣs / 45? minutes
Zacznijmy od początku
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
…tak koncepcyjnie
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Project CRaC
JVM
Byte Code Interpreter
Just-in-Time Compiler
Compiled Code 🚀
GraalVM
Project CRaC
ByteCode
public static int add(int a, int b) {
return a + b;
}
0: iload_1
1: iload_2
2: iadd
3: ireturn
javac
Project CRaC
ByteCode
0: iload_1
1: iload_2
2: iadd
3: ireturn
Project CRaC
ByteCode
0: iload_1
1: iload_2
2: iadd
3: ireturn
Project CRaC
ByteCode
0: iload_1
1: iload_2
2: iadd
3: ireturn
Project CRaC
ByteCode
0: iload_1
1: iload_2
2: iadd
3: ireturn
Project CRaC
HotSpot Analysis
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b) {
return a + b;
}
Project CRaC
HotSpot Analysis
Hot Spot
0: iload_1
1: iload_2
2: iadd
3: ireturn
Project CRaC
HotSpot Analysis
Hot Spot
0: iload_1
1: iload_2
2: iadd
3: ireturn
JIT
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Project CRaC
JVM
Byte Code Interpreter
C1 Compiler
Compiled Code 🚀
GraalVM
C2 Compiler
C1 - Client Compiler
C1 - Client Compiler
Client Compiler, zwany również C1, to rodzaj
kompilatora JIT zoptymalizowanego pod kątem
szybszego czasu startu. Stara się optymalizować
i kompilować kod tak szybko, jak to możliwe.
C2 - Client Compiler
C2 - Client Compiler
Kompilator serwera, zwany również C2, to rodzaj
kompilatora JIT zoptymalizowanego pod kątem
lepszej ogólnej wydajności.
C2 obserwuje i analizuje kod przez dłuższy czas
w porównaniu do C1. Pozwala to C2 na
dokonanie lepszych optymalizacji w
skompilowanym kodzie.
C2 - Client Compiler
Kompilator serwera, zwany również C2, to rodzaj
kompilatora JIT zoptymalizowanego pod kątem
lepszej ogólnej wydajności.
C2 obserwuje i analizuje kod przez dłuższy czas
w porównaniu do C1. Pozwala to C2 na
dokonanie lepszych optymalizacji w
skompilowanym kodzie.
Tiered Compilation
Wydajność
Start Czas
Interpreter
C1
C2
Tiered Compilation
Wydajność
Start Czas
Interpreter
C1
C2
Tiered Compilation
Wydajność
Start Czas
Interpreter
C1
C2
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Optymalizacja dynamiczna
Kompilator JIT może rekompilować części kodu
w trakcie działania programu dzięki pro
fi
lingu.
Pozwala to na optymalizacje oparte na
rzeczywistych danych z czasu wykonania, które
kompilatory statyczne nie są w stanie
uwzględnić.
Tiered Compilation
Nasz Kod Interpreter C1 C2
Code
Cache
Deoptimization
Zoptymalizowany
kod
Jeszcze bardziej
zoptymalizowany
kod
Ups…
Level 0
Pro
fi
ling Pro
fi
ling
Level 1
Level 2
Level 3 Level 4
Spekulatywna optymalizacja
Spekulatywna optymalizacja
public class DeoptimizationExample {
public static void main(String[] args) {
NumberAdder adder = new SimpleAdder();
for (int i = 0; i < 10000; i++) {
if (i == 5000) {
adder = new LoggingAdder();
}
adder.addRandomNumber(10);
}
}
}
interface NumberAdder {
void addRandomNumber(int base);
}
class SimpleAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
}
}
class LoggingAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
System.out.println("Computed value: " + result);
}
}
public class DeoptimizationExample {
public static void main(String[] args) {
NumberAdder adder = new SimpleAdder();
for (int i = 0; i < 10000; i++) {
if (i == 5000) {
adder = new LoggingAdder();
}
adder.addRandomNumber(10);
}
}
}
interface NumberAdder {
void addRandomNumber(int base);
}
class SimpleAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
}
}
class LoggingAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
System.out.println("Computed value: " + result);
}
}
public class DeoptimizationExample {
public static void main(String[] args) {
NumberAdder adder = new SimpleAdder();
for (int i = 0; i < 10000; i++) {
if (i == 5000) {
adder = new LoggingAdder();
}
adder.addRandomNumber(10);
}
}
}
interface NumberAdder {
void addRandomNumber(int base);
}
class SimpleAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
}
}
class LoggingAdder implements NumberAdder {
public void addRandomNumber(int base) {
double result = Math.random() + base;
System.out.println("Computed value: " + result);
}
}
Tiered Compilation
Nasz Kod Interpreter C1 C2
Code
Cache
Deoptimization
Zoptymalizowany
kod
Jeszcze bardziej
zoptymalizowany
kod
Ups…
Level 0
Pro
fi
ling Pro
fi
ling
Level 1
Level 2
Level 3 Level 4
Skomplikowane, co nie?
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
GraalVM
GraalVM
GraalVM is a high-performance JDK
distribution that compiles your Java
applications ahead of time into standalone
binaries. These binaries start instantly, provide
peak performance with no warmup, and use
fewer resources.
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
GraalVM
GraalVM
Kubernetes
GraalVM
GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Project CRaC
JVM
Byte Code Interpreter
C1 Compiler
Compiled Code 🚀
GraalVM in Just-In-Time (JIT) Compilation Mode
C2 Compiler
Project CRaC
GraalVM
Byte Code Interpreter
Compiled Code 🚀
GraalVM in Just-In-Time (JIT) Compilation Mode
Graal Compiler
Project CRaC
HotSpot Analysis
Hot Spot
0: iload_1
1: iload_2
2: iadd
3: ireturn
JIT
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Hot Spot
0: iload_1
1: iload_2
2: iadd
3: ireturn
Graal Compiler
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Hot Spot
0: iload_1
1: iload_2
2: iadd
3: ireturn
Graal Compiler
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
Project CRaC
GraalVM in Just-In-Time (JIT) Compilation Mode
GraalVM in Just-In-Time (JIT) Compilation Mode
Project CRaC
GraalVM
Byte Code Interpreter
Compiled Code 🚀
GraalVM in Just-In-Time (JIT) Compilation Mode
Graal Compiler
Project CRaC
Substrate VM
Compiled Code 🚀
GraalVM in Ahead-of-Time (AoT) Compilation Mode
Graal Compiler
public static int add(int a, int b) {
return a + b;
}
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Closed World Assumption
Closed World Assumption
ClassLoader.loadClass
MethodHandle
Proxy
Reflection
Wreszcie możemy przejść do Truf
fl
e
GraalVM
GraalVM in Truf
fl
e Mode
GraalVM in Truf
fl
e Mode
GraalVM in Truf
fl
e Mode
No i znowu dygresja
GraalVM in Truf
fl
e Mode
Jak możemy udowodnić, że ten program działa?
RICE’S THEOREM (1957)
KAŻDA NIETRYWIALNA WŁASNOŚĆ JĘZYKÓW REKURENCYJNIE PRZELICZALNYCH JEST NIEROZSTRZYGALNA
Statyczne typowania - Zbiór zasad do przestrzegania
F O R T R A N ( 1 9 5 7 )
Fortran (1957)
Fortran (1957)
Lower Bound of Correctness
Tradeoff: Easy to use / correct
List<Integer> integers = new ArrayList<>();
List rawList = integers;
rawList.add("hello");
try {
Integer num = integers.get(0);
} catch (ClassCastException e) {
System.out.println("Error: " + e.getMessage());
}
Dynamiczne Typowanie - Zarządzanie typami w runtime
function add (a, b) {
return a + b; }
RUNTIME
Wartość w kodzie
RUNTIME
value = 1
type = int
a
Wartość w kodzie
RUNTIME
Math.abs()
value = 1
type = int
a
Wszystko jest ok
value = 1
type = int
a
String.trim()
RUNTIME
Runtime Exception
value = 1
type = int
a
String.trim()
RUNTIME
Runtime Exception
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Narzut wydajnościowy
function add(x, y) {
return x + y;
}
// Monomorphic usage
console.log(add(1, 2));
console.log(add(3, 4));
// Polymorphic usage
console.log(add(1, 2));
console.log(add("3", "4"));
Dynamic Typing
Monomor
fi
zm, w kontekście optymalizacji
silników dynamicznych, odnosi się do sytuacji, w
której funkcja jest konsekwentnie wywoływana z
argumentami tego samego typu.
Dynamic Typing
Polimor
fi
zmem: Funkcja jest wywoływana z
argumentami różnych typów. Wymaga to od
silnika obsługi wielu przypadków i może
prowadzić do mniej efektywnego kodu.
Megamor
fi
zmem: Funkcja jest wywoływana z
wieloma różnymi typami argumentów, co czyni
niemal niemożliwą optymalizację przez silnik.
function add(a, b) {
return a + b;
}
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Wracamy do Truf
fl
e
GraalVM in Truf
fl
e Mode
GraalVM
Byte Code Interpreter
Compiled Code 🚀
Graal Compiler
Language Interpreter
GraalVM in Truf
fl
e Mode
GraalVM
Language Interpreter
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInfo;
@TypeSystemReference(MyTypeSystem.class) // Define the types recognized in your language
@NodeInfo(shortName = "add")
public abstract class AddNode extends Node {
abstract Object execute(Object a, Object b);
@Specialization
protected int addIntegers(int a, int b) {
return a + b;
}
@Specialization
protected double addDoubles(double a, double b) {
return a + b;
}
// Can add more specializations (e.g., for adding strings, booleans, etc.)
}
GraalVM
System Operacyjny
JVM
NASZA APLIKACJA
add
a b
R
AST z niezainicjowanymi Node
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Pro
fi
ling AST
U
S
G
I
D
Main
add
a b
R Tranzycje
add
a b
R
Ustabilizowane, monformiczne AST
Main
add
a b
R
Po raz ponownie - spekulatywna optymalizacja
add
a b
R
Guard Nodes
Main
add
a b
R
a & b instanceof
double
a & b instanceof
String
Project CRaC
Partial Evaluation
Graal Compiler
add
a b
R
Partial Evaluation
Main
add
a b
R
a & b instanceof
double
add
a
R
B a & b instanceof
String
add
a b
R
Partial Deoptimization & Repro
fi
ling
add
a b
R
a & b instanceof
double
a & b instanceof
String
add
a
R
B
Main
add
a b
R
Partial Deoptimization & Repro
fi
ling
Main
add
a b
R
a & b instanceof
double
U
S
G
I
D
Tranzycje
Project CRaC
JVM
Byte Code Interpreter
C1 Compiler
Compiled Code 🚀
GraalVM in Just-In-Time (JIT) Compilation Mode
C2 Compiler
Language Interpreter
No dobra, to jak to skonsumować
GraalVM in Truf
fl
e Mode
GraalVM
Language Interpreter
GraalVM as library
try (Context context = Context.create()) {
Value result = context.eval("js",
"({ " +
"id : 42," +
"text : '42', " +
"arr : [1,42,3] " +
"}))");
assert result.hasMembers();
int id = result.getMember("id").asInt();
assert id == 42;
String text = result.getMember("text").asString();
assert text.equals("42");
Value array = result.getMember("arr");
assert array.hasArrayElements();
assert array.getArraySize() == 3;
assert array.getArrayElement(1).asInt() == 42;
}
GraalVM as library
GraalVM as library
public static class MyClass {
public int id = 42;
public String text = "42";
public int[] arr = new int[]{1, 42, 3};
public Callable<Integer> ret42 = () -> 42;
public static void main(String[] args) {
try (Context context = Context.newBuilder()
.allowAllAccess(true)
.build()) {
context.getBindings(“js").putMember(
"java0bj", new MyClass());
boolean valid = context.eval("js",
" java0bj.id == 42" +
" && java0bj.text == '42'" +
" && java0bj.arr[1] == 42" +
" && java0bj.ret42() == 42")
.asBoolean();
assert valid == true;
}
}
}
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
GraalVM Runtime (SubstratVM)
espresso
GraalVM JIT Compiler
GraalVM Runtime (SubstratVM)
espresso
GraalVM JIT Compiler
Truf
fl
e
GraalVM Runtime (SubstratVM)
espresso
GraalVM Runtime (SubstratVM)
GraalVM JIT Compiler
Truf
fl
e
espresso
Our Application
espresso
GraalVM JIT Compiler
Truf
fl
e
Espresso
GraalVM Runtime (SubstratVM)
espresso
GraalVM JIT Compiler
Truf
fl
e
Espresso
GraalVM Runtime (SubstrateVM)
GraalVM in Just-In-Time (JIT) Compilation Mode
GraalVM in Just-In-Time (JIT) Compilation Mode
Espresso
GraalVM
Byte Code Interpreter
Compiled Code 🚀
Graal Compiler
Espresso
JVM
Byte Code Interpreter
C1 Compiler
Compiled Code 🚀
C2 Compiler
Espresso
Our application
Espresso
Espresso
Espresso
Espresso
GraalVM in Just-In-Time (JIT) Compilation Mode
GraalVM in Just-In-Time (JIT) Compilation Mode
vived.io
Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM
Thank you 🙇
@ArturSkowronski

More Related Content

Kopiąc Trufle - Odkrywanie tajemnic najmniej zrozumiałego elementu GraalVM