POLYGLOT
WITH
GRAALVM
O S C O N 2 0 1 9 / M I C H A E L H U N G E R / @ M E S I R I I
POLYGLOT WITH GRAALVM O S C O N 2 0 1 9 / M I C H A E L H U N - - PowerPoint PPT Presentation
POLYGLOT WITH GRAALVM O S C O N 2 0 1 9 / M I C H A E L H U N G E R / @ M E S I R I I MICHAEL HUNGER Caretaker General, Neo4j Head of Neo4j Labs Disturber of the Peace Java Champion (graphs)-[:ARE]->(everywhere) Twitter &
O S C O N 2 0 1 9 / M I C H A E L H U N G E R / @ M E S I R I I
MICHAEL HUNGER
Caretaker General, Neo4j Head of Neo4j Labs Disturber of the Peace Java Champion
(graphs)-[:ARE]->(everywhere) Twitter & Medium: @mesirii
WRITING ABOUT GRAAL SINCE 2014
WARNING: WHIRLWIND TOUR DONT‘T READ THE CODE
NOT EVERYONE IS A JAVA DEVELOPER!
POLYGLOT?
We have:
–Scala, Groovy, Kotlin, Clojure, Frege … –JRuby, Jython, … L
We want:
performance
WHATS IN FOR ME?
–Run JavaScript, Ruby, R, Python, LLVM code efficiently on the JVM
–Binaries for Language Runtimes –AOT compiled native images of your applications
Lego box
WHO READS THE INSTRUCTIONS
HOW CAN I USE IT?
gu (graal-updater) Utility js/node, ruby, python, R runtimes native-image tool
https://www.graalvm.org/downloads/
JAVA 11
sdk use java 11.0.1-open java -Diterations=3 CountUppercase \ I‘m happy to be back in Portland, OR for OSCON 2019
GRAALVM
sdk install java 19.1.0-grl gu install R python ruby native-image gu list ComponentId Version Component name
19.1.0 GraalVM Core R 19.1.0 FastR native-image 19.1.0 Native Image python 19.1.0 Graal.Python ruby 19.1.0 TruffleRuby java –version OpenJDK 64-Bit GraalVM CE 19.1.0 (build 25.212-b03-jvmci-20-b04, mixed mode)
Lego Instructions built
PYTHON
# graalpython fac.py 2500 import sys def fac(n): if n==1: return 1 else: return fac(n-1)*n x = int(sys.argv[1]) print("Factorial for {} is {}" .format(x,fac(x)))
LLVM BITCODE
#include <stdio.h> int main() { printf("Hello from GraalVM!\n"); return 0; } clang -c -O1 -emit-llvm hello.c lli hello.bc
R --version:graalvm data <- "https://raw.githubusercontent.com/selva86/datasets/master/proglanguages.csv" library(ggplot2) library(treemapify) proglangs <- read.csv(data) ggplot(proglangs, aes(area = value, fill = parent, label = id, subgroup = parent)) + geom_treemap() + geom_treemap_subgroup_border() + geom_treemap_subgroup_text() + geom_treemap_text()
JS POLYGLOT
node --version:graalvm node --jvm const BigInteger = Java.type("java.math.BigInteger") let a = new BigInteger("10") .add(new BigInteger("8") .multiply(new BigInteger("4"))) console.log(a.toString()) > 42
OPTIMIZING COMPILER IN JAVA
Create an extensible, modular, dynamic, and aggressive compiler using object-
based and visualizable intermediate representation, and Java snippets. —Thomas Würthinger
G R A A L ! ?
–e.g. inlining POJOS/DTOS –Inlining streams –Speeds up many typical Java/Scala programs
BOX OF JOY
GRAAL ❤ TRUFFLE ❤ SUBSTRATE
GraalVM is a high-performance, embeddable, polyglotVirtual Machine for running applications written in JavaScript, Python, Ruby, R, JVM-based languages like Java, Scala, Kotlin, and LLVM-based languages such as C and C++. Additionally, GraalVM allows efficient interoperability between programming languages and compiling Java applications ahead-of-time into native executables for faster startup time and lower memory
https://github.com/oracle/graal/releases
BIGGER ON THE INSIDE
– TruffleRuby / FastR
VM in Java
– Project Metropolis
– Substrate-VM – Truffle – Graal Compiler – AOT Compilation
HISTORY
GRAALVM
– 19.1.1 (quarterly release)
– JVM 1.8.x – Node.js 10.x / ECMAScript 2019 – LLVM bitcode runtime
– Truffle Runtime – Language Packs (via gu) – Native Image AOT
– Community (GPL v2 w/ CP-Exception – Enterprise (faster, sandboxing, commercial support) – Oracle Database Engine
MACHINE CODE BABY
NATIVE IMAGE
Spring (soon)
– no reflection, no later classloading, no initializer dynamics – Slow build
https://medium.com/graalvm/lightweight-cloud-native-java-applications- 35d56bc45673
L A N G U A G E R U N T I M E
TRUFFLE
– T
esting
TRUFFLE + GRAAL
TRUFFLE GRAAL
steady state assumption
assumptions
T R U F F L E E X A M P L E L A N G U A G E
@NodeInfo(shortName = "+") public abstract class SLAdditionNode extends SLBinaryNode { @Fallback protected Object typeError(Object left, Object right) { throw SLException.typeError(this, left, right); } @Specialization(rewriteOn = ArithmeticException.class) protected long add(long left, long right) { return Math.addExact(left, right); } @Specialization @TruffleBoundary protected SLBigNumber add(SLBigNumber left, SLBigNumber right) { return new SLBigNumber(left.getValue().add(right.getValue())); } @Specialization(guards = "isString(left, right)") @TruffleBoundary protected String add(Object left, Object right) { return left.toString() + right.toString(); } protected boolean isString(Object a, Object b) {…}
BOX OF COLORS
JAVASCRIP T
(10.15.2) compat
https://www.graalvm.org/docs/reference-manual/languages/js/
GRAAL PYTHON
GraalVMs
https://www.graalvm.org/docs/reference-manual/languages/python/
FAST-R
implementations
https://www.graalvm.org/docs/reference-manual/languages/r/
TRUFFLE RUBY
https://www.graalvm.org/docs/reference-manual/languages/ruby/
LLVM
in Java via Truffle
– sandbox libraries – virtualize syscalls – memory on managed heap
https://medium.com/graalvm/safe-and-sandboxed-execution-of- native-code-f6096b35c360
DO WHAT YOU WANT THURSDAY
TRUFFLE
– eval – bind – invoke
docs.oracle.com/en/graalvm/enterprise/19/sdk/org/graalvm/polyglot/Context.html
VALUE
– Scalar – List/Array – Host/Proxy Object w/ Members – Function/Invoke/Executable
conversions
support
docs.oracle.com/en/graalvm/enterprise/19/sdk/org/graalvm/polyglot/Value.html
CAPABILITIES
Polyglot support: --polyglot Eval
file="./my_ruby_file.rb") Export / Import
Object Access
JAVA INTEROP JVM Support: --jvm Flag Import
Java.import “java.util.UUID“ java.type("java.math.BigInteger") from java.util import ArrayList
Helpers
/ instance_of
Access
// gu install ruby python R // groovy PolyTest1.groovy @Grab("org.graalvm.sdk:graal-sdk:19.1.0") import org.graalvm.polyglot.* ctx = Context.newBuilder().allowAllAccess(true).build() ctx.eval("js", "print('Hello JavaScript!');") ctx.eval("R", "print('Hello R!');"); ctx.eval("ruby", "puts 'Hello Ruby!'"); ctx.eval("python", "print('Hello Python!')");
import java generic = java.type('org.testcontainers.containers.GenericContainer') container = generic('nginx') container.setExposedPorts([80]) container.start(); print('%s:%s' % (container.getContainerIpAddress(), container.getMappedPort(80)));
https://medium.com/graalvm/using-testcontainers-from-a-node-js-application-3aa2273bf3bb
#include <stdio.h> #include <curl/curl.h> long request() { CURL *curl = curl_easy_init(); long response_code = -1; if(curl) { CURLcode res; curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); res = curl_easy_perform(curl); if(res == CURLE_OK) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); } curl_easy_cleanup(curl); } return response_code; }
// clang -c -O1 -emit-llvm use-curl.c && groovy CurlTest.groovy @Grab("org.graalvm.sdk:graal-sdk:1.9.10") import org.graalvm.polyglot.* polyglot = Context.newBuilder() .allowAllAccess(true) .option("llvm.libraries", "/usr/lib/libcurl.dylib") .build() source = Source .newBuilder("llvm", new File("use-curl.bc")) .build() result = polyglot.eval(source) responseValue = result.getMember("request").execute() responseCode = responseValue.asLong() print(responseCode)
R+PYTHON
pycode <- ‚ library polyglot PI=polyglot.import("PI") def area(radius): return 2*radius*PI area ' export("PI",pi) area <- eval.polyglot("python",pycode) print(area(5))
JAVA+R
@Value(value = "classpath:plot.R") private Resource rSource; @Autowired private Function<DataHolder, String> plotFunction; @Bean Function<DataHolder, String> getPlotFunction(@Autowired Context ctx) { Context ctx = Context.newBuilder().allowAllAccess(true).build(); Source source = Source.newBuilder("R", rSource.getURL()).build(); return ctx.eval(source).as(Function.class); } @RequestMapping(value = "/load", produces = "image/svg+xml") public synchronized ResponseEntity<String> load() { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.set("Refresh", "1"); double load = getOperatingSystemMXBean().getSystemLoadAverage(); String svg = plotFunction.apply(new DataHolder(load)); return new ResponseEntity<String>(svg,responseHeaders,HttpStatus.OK); }
library(ggplot2) data <<- numeric(100) function(dataHolder) { svg() data <<- c(data[2:100],dataHolder$value) plot <- ggplot(data= data.frame(systemLoad=data, time =-99:0), aes(x=time, y=systemLoad, group=1)) + geom_line(color="orange") + expand_limits(x=0, y=0) print(plot) svg.off() }
Context context = Context.newBuilder().allowAllAccess(true).build(); Set<String> languages = context.getEngine().getLanguages().keySet();
String language = languages.iterator().next(); while (true) {
String line = input.readLine(); if (line == null) break; else if (languages.contains(line)) language = line; else { Source source = Source.newBuilder(language, line, "<shell>") .interactive(true).buildLiteral(); context.eval(source); } }
POLYGLOT OPTIONS
Print GraalVM version information and exit.
Print GraalVM version information and continue execution.
Start with Debugger
Run using the native launcher with limited Java access
Run on the JVM with Java access.
Run with all other guest languages accessible.
Pass options to the host VM
Options for all installed languages, tools, host VM
Internal options for debugging language impl and tools.
MAKING OUR LIFES EASIER
MORE POWER TO THE MACHINE
WHY?
transfers
– PL/SQL – Java
– public packages (e.g. validators, data science, visualization) – domain specific code
EXTENDING DATABASES
– native library integration
R, Python with dbjs
dbjs deploy -u <user> -p <pass>
https://www.graalvm.org/docs/examples/mle-oracle/
CREATE OR REPLACE JAVASCRIPT SOURCE NAMED "hello.js" AS module.exports.greet = function(a) { return "Hello " + a; }; CREATE OR REPLACE FUNCTION greet(a IN VARCHAR2) RETURN VARCHAR2 AS LANGUAGE JAVASCRIPT NAME 'hello.js.greet(a string) return string‘; SELECT greet('GraalVM') FROM DUAL; Hello GraalVM
(GRAPHS)-[:ARE]->(EVERYWHERE)
NEO4J IN A TWEET
@Neo4j is an open-source native graph database designed to store, manage and query highly connected data efficiently with the Cypher Query Language. It runs transactional and analytic workloads, supports visualization and is extendable with custom functions.
neo4j.com/developer
NEO4J
Language
https://github.com/neo4j-examples/oscon-graph
// top 10 talks (that I‘ve not see) // that peers who like the same talks I did also liked MATCH (me:User {name:“Michael“})
WHERE NOT (me)-[:FAVORITED]->(reco) RETURN reco.name, count(*) AS freq ORDER BY freq DESC LIMIT 10
P U T YO U R S M A RT S I N T H E DATA B A S E
NEO4J CUSTOM FUNCTIONS
with Functions
Procedures
Language
@UserFunction @Description(„Generates an UUID“) public String uuid() { return UUID.randomUUID().toString(); } CREATE (:Event {id: uuid(), name:“Graph Algorithms“ });
U S I N G T R U F F L E A P I S & G R A A L V M
POLYGLOT FUNCTIONS
params, or
language functions
restart / in cluster
A D H O C E X E C U T I O N
@Procedure(„scripts.execute“) public Object executeCode(String lang, String code, Map<String,Object> props) { Context ctx = Context.newBuilder().allowAllAccess(true).build(); Bindings bindings = ctx.getBindings(); props.forEach(bindings::putMember); bindings.putMember("label", ctx.eval("js", "s => org.neo4j.graphdb.Label.label(s)")); bindings.putMember("db", graphDatabase); return ctx.eval(lang, code).asHostObject(); }
E VA L C O D E
CALL scripts.execute(' Java.import "org.neo4j.graphdb.Label db = Polyglot.import("db") props = db.findNode(Label.label("Event"), "name",“OSCON") .getAllProperties().entrySet().toArray() Polyglot.as_enumerable(props) .map{|e| "#{e.getKey()} -> #{e.getValue()}"} .join(",") ',{},'ruby')
DY N A M I C A L LY
Context ctx = Context.newBuilder().allowAllAccess(true).build() @Procedure(„scripts.register“) public void registerFunction(String lang, String name, String code) { Value function = ctx.eval(lang, code); ctx.getBindings(lang) .putMember(name, function); }
@UserFunction(„scripts.run“) public Object executeFun(String lang, String name, Object…args) { return ctx.getBindings(lang) .getMember(name) .execute(params).asHostObject(); }
@UserFunction public void registerFunction(String code, String name, String lang) { ctx.getBindings(lang).putMember(name, ctx.eval(code)); procedures.register(new BasicUserFunction(signature(name)) { @Override public AnyValue apply(org.neo4j.proc.Context c, AnyValue[] input) { return resultOf(context.getBindings(lang).getMember(name) .execute(paramsFor(input))); } }); }
A U TO L O A D S C R I P T F I L E S
watchService = FileSystems.getDefault().newWatchService(); pathName = new File(scriptsDir, target.getDirName()) pathToWatch = getTargetPath(pathName); pathToWatch.register(watchService, ENTRY_CREATE,ENTRY_DELETE, ENTRY_MODIFY); public void run() { WatchKey watchKey; while ((watchKey = watchService.take()) != null) { for (WatchEvent<?> event : watchKey.pollEvents()) updateScript(event.kind(), event.context()); } }
public class ScriptFunction implements CallableUserFunction { private final UserFunctionSignature signature; private final String name; private final String sourceCode; private transient volatile Source source; public ScriptFunction(String language, String name, String sourceCode) { this.name = name; this.sourceCode = sourceCode; this.source = Source.newBuilder(this.language, this.sourceCode, this.name).build(); this.signature = generateSignature(); } private UserFunctionSignature generateSignature() { final QualifiedName qualifiedName = new QualifiedName(Arrays.asList("scripts", "fn"), name); final List<FieldSignature> input = IntStream.range(0, numberOfArguments); .mapToObj(i -> FieldSignature.inputField("p" + i, NTAny, DefaultParameterValue.nullValue(NTAny))) .collect(toList()); return new UserFunctionSignature(qualifiedName, input, NTAny, null, new String[0], null, false); }
@Override public AnyValue apply(Context ctx, AnyValue[] input) throws ProcedureException { try (org.graalvm.polyglot.Context context = PolyglotContext.newInstance()) { GraphDatabaseAPI db = ctx.get(Context.DATABASE_API); Log log = ctx.get(Context.DEPENDENCY_RESOLVER).resolveDependency(LogService.class) .getUserLog(ScriptFunction.class); Value bindings = context.getPolyglotBindings(); bindings.putMember("db", db); bindings.putMember("log", log); Value langBindings = context.getBindings(language); langBindings.putMember(name, context.eval(source)); return resultFor(langBindings.getMember(name).invoke(input)); } }
private AnyValue resultFor(Value result) { if (result.isNull()) { return null; } if (result.isNumber()) { return ValueUtils.asAnyValue(result.asDouble()); } if (result.isBoolean()) { return ValueUtils.asAnyValue(result.asBoolean()); } if (result.isHostObject()) { return ValueUtils.asAnyValue(result.asHostObject()); } return ValueUtils.asAnyValue(result.asString()); }
NEXT STEPS
– Graph processing / algorithms – Data Science / ML / graph_net – Large Scale Plotting – Investigate GraphBlas (C-Library)
AND EXCELLENT
THE GOOD
– All the languages – JVM Interop – Polyglot Interop
Oracle Team
was really easy
AND UGLY
THE BAD
costly
collection types (map/hash/dict) and (list/collection) – only for arrays
ALL THE THINGS
MORE
~/graalvm-ten-things-12d9111f307d
package compat checker
Twitter & Medium: @mesirii
Graphs in AI and ML Alicia Frame, Senior Data Scientist, Neo4j Jake Graham, Lead Product Manager for AI and Graph Analytics Intro to Neo4j for Developers Jennifer Reif, Developer Relations Engineer, Neo4j Neo4j Bolt Driver Architecture Now and in The Future Nigel Small, Tech Lead for Neo4j Drivers team GRANDstack: Graphs ALL the Way Down William Lyon, Software Engineer, Neo4j Labs All-new SDN-RX: Reactive Spring Data Neo4j Gerrit Meier, Software Engineer, Neo4j Graph Embeddings Alicia Frame, Senior Data Scientist, Neo4j Graph Modeling Tips and Tricks Max De Marzi, Field Engineer and Graph Expert, Neo4j APOC Pearls -The best Tips and Tricks Michael Hunger, Director of Neo4j Labs Visualizing Graph Data in JavaScript Will Lyon, Software Engineer, Neo4j Labs Creating a Data Marvel (Comics) with Spring and Neo4j Jennifer Reif, Developer Relations Engineer, Neo4j
Keynote and Announcements
Emil Eifrem, CEO and Co-Creator of Neo4j
October 10 8am NYC, 1pm London, 530pm Mumbai
QUESTIONS IN HALLWAY