Last active
February 26, 2018 01:29
-
-
Save erickj/30aa179a73ab1e2a2b7355b63a34b487 to your computer and use it in GitHub Desktop.
TinkerPop traversal execution timing - https://groups.google.com/forum/#!topic/gremlin-users/0HCWv1Zlsw8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TraversalBench... | |
Run 1: g.V().outE() | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 19.133056ms | |
per iteration: 1.913306ms | |
warmup(100) done in: | |
total: 28.484113ms | |
per iteration: 0.284841ms | |
warmup(1000) done in: | |
total: 125.944196ms | |
per iteration: 0.125944ms | |
result time: 0.154849ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 50.031126ms | |
per iteration: 5.003113ms | |
warmup(100) done in: | |
total: 23.731849ms | |
per iteration: 0.237318ms | |
warmup(1000) done in: | |
total: 125.819753ms | |
per iteration: 0.125820ms | |
result time: 0.144291ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 1.997528ms | |
per iteration: 0.199753ms | |
warmup(100) done in: | |
total: 5.947392ms | |
per iteration: 0.059474ms | |
warmup(1000) done in: | |
total: 62.082170ms | |
per iteration: 0.062082ms | |
result time: 0.128680ms | |
TraversalBench... | |
Run 1: g.V(1).out('knows').values('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 6.695467ms | |
per iteration: 0.669547ms | |
warmup(100) done in: | |
total: 11.061351ms | |
per iteration: 0.110614ms | |
warmup(1000) done in: | |
total: 53.746260ms | |
per iteration: 0.053746ms | |
result time: 0.083552ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 36.414791ms | |
per iteration: 3.641479ms | |
warmup(100) done in: | |
total: 12.565176ms | |
per iteration: 0.125652ms | |
warmup(1000) done in: | |
total: 97.489639ms | |
per iteration: 0.097490ms | |
result time: 0.159088ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 1.179642ms | |
per iteration: 0.117964ms | |
warmup(100) done in: | |
total: 11.532068ms | |
per iteration: 0.115321ms | |
warmup(1000) done in: | |
total: 79.734606ms | |
per iteration: 0.079735ms | |
result time: 0.091599ms | |
TraversalBench... | |
Run 3: g.V().hasLabel('person').choose(values('age').is(lte(30)), __.in(), __.out()).values('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 39.137261ms | |
per iteration: 3.913726ms | |
warmup(100) done in: | |
total: 72.466179ms | |
per iteration: 0.724662ms | |
warmup(1000) done in: | |
total: 236.760206ms | |
per iteration: 0.236760ms | |
result time: 0.353925ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 24.835064ms | |
per iteration: 2.483506ms | |
warmup(100) done in: | |
total: 54.256237ms | |
per iteration: 0.542562ms | |
warmup(1000) done in: | |
total: 254.830645ms | |
per iteration: 0.254831ms | |
result time: 0.396736ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 6.961101ms | |
per iteration: 0.696110ms | |
warmup(100) done in: | |
total: 31.017225ms | |
per iteration: 0.310172ms | |
warmup(1000) done in: | |
total: 198.093553ms | |
per iteration: 0.198094ms | |
result time: 0.355522ms | |
TraversalBench... | |
Run 4: g.V().has('name','marko').repeat(out()).times(2).groupCount().by('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 5.775404ms | |
per iteration: 0.577540ms | |
warmup(100) done in: | |
total: 33.639707ms | |
per iteration: 0.336397ms | |
warmup(1000) done in: | |
total: 104.268361ms | |
per iteration: 0.104268ms | |
result time: 0.144245ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 9.762038ms | |
per iteration: 0.976204ms | |
warmup(100) done in: | |
total: 24.413798ms | |
per iteration: 0.244138ms | |
warmup(1000) done in: | |
total: 159.212410ms | |
per iteration: 0.159212ms | |
result time: 0.246301ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 3.752110ms | |
per iteration: 0.375211ms | |
warmup(100) done in: | |
total: 29.596277ms | |
per iteration: 0.295963ms | |
warmup(1000) done in: | |
total: 123.809216ms | |
per iteration: 0.123809ms | |
result time: 0.224183ms |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TraversalBench... | |
Run 1: g.V().outE() | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 23.722339ms | |
per iteration: 2.372234ms | |
warmup(100) done in: | |
total: 29.206641ms | |
per iteration: 0.292066ms | |
warmup(1000) done in: | |
total: 127.089622ms | |
per iteration: 0.127090ms | |
result time: 0.174406ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 47.175194ms | |
per iteration: 4.717519ms | |
warmup(100) done in: | |
total: 36.383286ms | |
per iteration: 0.363833ms | |
warmup(1000) done in: | |
total: 140.792184ms | |
per iteration: 0.140792ms | |
result time: 0.166214ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 21.872346ms | |
per iteration: 2.187235ms | |
warmup(100) done in: | |
total: 138.714526ms | |
per iteration: 1.387145ms | |
warmup(1000) done in: | |
total: 516.724577ms | |
per iteration: 0.516725ms | |
result time: 0.485695ms | |
TraversalBench... | |
Run 1: g.V(1).out('knows').values('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 7.586529ms | |
per iteration: 0.758653ms | |
warmup(100) done in: | |
total: 8.740898ms | |
per iteration: 0.087409ms | |
warmup(1000) done in: | |
total: 67.843517ms | |
per iteration: 0.067844ms | |
result time: 0.080826ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 55.004259ms | |
per iteration: 5.500426ms | |
warmup(100) done in: | |
total: 16.308394ms | |
per iteration: 0.163084ms | |
warmup(1000) done in: | |
total: 133.953688ms | |
per iteration: 0.133954ms | |
result time: 0.207327ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 7.260053ms | |
per iteration: 0.726005ms | |
warmup(100) done in: | |
total: 63.388740ms | |
per iteration: 0.633887ms | |
warmup(1000) done in: | |
total: 445.554497ms | |
per iteration: 0.445554ms | |
result time: 0.463575ms | |
TraversalBench... | |
Run 3: g.V().hasLabel('person').choose(values('age').is(lte(30)), __.in(), __.out()).values('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 31.304910ms | |
per iteration: 3.130491ms | |
warmup(100) done in: | |
total: 68.511333ms | |
per iteration: 0.685113ms | |
warmup(1000) done in: | |
total: 293.160874ms | |
per iteration: 0.293161ms | |
result time: 0.289666ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 23.613168ms | |
per iteration: 2.361317ms | |
warmup(100) done in: | |
total: 52.100115ms | |
per iteration: 0.521001ms | |
warmup(1000) done in: | |
total: 235.183739ms | |
per iteration: 0.235184ms | |
result time: 0.346527ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 39.361747ms | |
per iteration: 3.936175ms | |
warmup(100) done in: | |
total: 137.304990ms | |
per iteration: 1.373050ms | |
warmup(1000) done in: | |
total: 987.066920ms | |
per iteration: 0.987067ms | |
result time: 1.086295ms | |
TraversalBench... | |
Run 4: g.V().has('name','marko').repeat(out()).times(2).groupCount().by('name') | |
!!! | |
!!! Java Native traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 7.924316ms | |
per iteration: 0.792432ms | |
warmup(100) done in: | |
total: 30.954189ms | |
per iteration: 0.309542ms | |
warmup(1000) done in: | |
total: 139.285917ms | |
per iteration: 0.139286ms | |
result time: 0.177736ms | |
!!! | |
!!! Script Engine traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 8.691457ms | |
per iteration: 0.869146ms | |
warmup(100) done in: | |
total: 23.694427ms | |
per iteration: 0.236944ms | |
warmup(1000) done in: | |
total: 165.945313ms | |
per iteration: 0.165945ms | |
result time: 0.214160ms | |
!!! | |
!!! Bytecode traversal !!! | |
!!! | |
warmup(10) done in: | |
total: 6.351670ms | |
per iteration: 0.635167ms | |
warmup(100) done in: | |
total: 75.253326ms | |
per iteration: 0.752533ms | |
warmup(1000) done in: | |
total: 522.935322ms | |
per iteration: 0.522935ms | |
result time: 0.638993ms |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.vos.graphs; | |
import static org.apache.tinkerpop.gremlin.process.traversal.P.lte; | |
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.in; | |
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out; | |
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.values; | |
import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine; | |
import org.apache.tinkerpop.gremlin.jsr223.JavaTranslator; | |
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; | |
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; | |
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; | |
import org.apache.tinkerpop.gremlin.structure.Graph; | |
import org.apache.tinkerpop.gremlin.structure.io.IoCore; | |
import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONReader; | |
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.concurrent.Callable; | |
import javax.script.CompiledScript; | |
import javax.script.ScriptEngine; | |
import javax.script.ScriptException; | |
class TraversalBench { | |
private static final Graph graph = TinkerFactory.createModern(); | |
private static final GraphTraversalSource g = graph.traversal(); | |
private static final boolean TIMED_COMPILE = true; | |
public static void main(String[] args) { | |
run1(); | |
run2(); | |
run3(); | |
run4(); | |
} | |
static void run1() { | |
System.out.println("TraversalBench..."); | |
System.out.println("Run 1: g.V().outE()"); | |
List<?> javaNativeResults = runJavaNativeTraversal(g.V().outE()); | |
List<?> groovyResults = runGroovyTraversal("g.V().outE()"); | |
List<?> bytecodeResults = runBytecodeTraversal(g.V().outE()); | |
assertResultsMatch(javaNativeResults, groovyResults, bytecodeResults); | |
} | |
static void run2() { | |
System.out.println("TraversalBench..."); | |
System.out.println("Run 1: g.V(1).out('knows').values('name')"); | |
List<?> javaNativeResults = runJavaNativeTraversal(g.V(1).out("knows").values("name")); | |
List<?> groovyResults = runGroovyTraversal("g.V(1).out('knows').values('name')"); | |
List<?> bytecodeResults = runBytecodeTraversal(g.V(1).out("knows").values("name")); | |
assertResultsMatch(javaNativeResults, groovyResults, bytecodeResults); | |
} | |
static void run3() { | |
System.out.println("TraversalBench..."); | |
System.out.println("Run 3: g.V().hasLabel('person').choose(values('age').is(lte(30)), __.in(), __.out()).values('name')"); | |
List<?> javaNativeResults = runJavaNativeTraversal( | |
g.V().hasLabel("person").choose(values("age").is(lte(30)), in(), out()).values("name")); | |
List<?> groovyResults = runGroovyTraversal( | |
"g.V().hasLabel('person').choose(values('age').is(lte(30)), __.in(), __.out()).values('name')"); | |
List<?> bytecodeResults = runBytecodeTraversal( | |
g.V().hasLabel("person").choose(values("age").is(lte(30)), in(), out()).values("name")); | |
assertResultsMatch(javaNativeResults, groovyResults, bytecodeResults); | |
} | |
static void run4() { | |
System.out.println("TraversalBench..."); | |
System.out.println("Run 4: g.V().has('name','marko').repeat(out()).times(2).groupCount().by('name')"); | |
List<?> javaNativeResults = runJavaNativeTraversal( | |
g.V().has("name","marko").repeat(out()).times(2).groupCount().by("name")); | |
List<?> groovyResults = runGroovyTraversal( | |
"g.V().has('name','marko').repeat(out()).times(2).groupCount().by('name')"); | |
List<?> bytecodeResults = runBytecodeTraversal( | |
g.V().has("name","marko").repeat(out()).times(2).groupCount().by("name")); | |
assertResultsMatch(javaNativeResults, groovyResults, bytecodeResults); | |
} | |
/** | |
* Serialization method group threads: | |
* https://groups.google.com/forum/#!topic/gremlin-users/0HCWv1Zlsw8 (marko's email: JavaTranslator vs. GroovyTranslator and Gremlin bytecode compilation speeds) | |
* https://groups.google.com/forum/#!msg/gremlin-users/R7qQbJXWcH8/iEcvJaVVBAAJ (marko's email: Traveral ByteCode and Translators) | |
* https://groups.google.com/forum/#!topic/gremlin-users/UuxzWQTl1x4 (how to convert dsl script to Traversal bytecode) | |
* | |
*/ | |
static List<?> runJavaNativeTraversal(GraphTraversal<?, ?> t) { | |
System.out.println("!!!"); | |
System.out.println("!!! Java Native traversal !!!"); | |
System.out.println("!!!"); | |
return TraversalBench.<List<?>>runIterations(() -> { | |
GraphTraversal.Admin<?, ?> adminClone = t.asAdmin().clone(); | |
return adminClone.toList(); | |
}); | |
} | |
/** | |
* Groovy Script engine: | |
* http://tinkerpop.apache.org/javadocs/current/full/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.html | |
* | |
* https://docs.oracle.com/javase/7/docs/api/javax/script/ScriptEngine.html#eval(java.lang.String) | |
*/ | |
static List<?> runGroovyTraversal(String t) { | |
System.out.println("!!!"); | |
System.out.println("!!! Script Engine traversal !!!"); | |
System.out.println("!!!"); | |
CompiledScript precompiled; | |
GremlinGroovyScriptEngine e = new GremlinGroovyScriptEngine(); | |
try { | |
precompiled = e.compile(t + ".toList()"); | |
} catch (ScriptException ex) { | |
throw new RuntimeException(ex); | |
} | |
List<?> result = (List<?>)TraversalBench.<Object>runIterations(() -> { | |
e.put("g", g); | |
if (TIMED_COMPILE) { | |
return e.eval(t + ".toList()"); | |
} | |
return precompiled.eval(); | |
}); | |
try { | |
e.close(); | |
} catch (Exception ex) { | |
throw new RuntimeException(ex); | |
} | |
return result; | |
} | |
/** | |
* See tinerpop gremlin-server: | |
* https://github.com/apache/tinkerpop/blob/master/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java#L367 | |
* https://github.com/apache/tinkerpop/blob/master/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/message/RequestMessage.java | |
* | |
* Graph Traversal Serialization: | |
* https://github.com/apache/tinkerpop/blob/master/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js | |
* http://tinkerpop.apache.org/docs/current/dev/io/#_bytecode_2 | |
* | |
* GraphSON: | |
* http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONWriter.html | |
* http://tinkerpop.apache.org/javadocs/current/core/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.html | |
*/ | |
static List<?> runBytecodeTraversal(GraphTraversal<?, ?> t) { | |
System.out.println("!!!"); | |
System.out.println("!!! Bytecode traversal !!!"); | |
System.out.println("!!!"); | |
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
try { | |
graph.io(IoCore.graphson()).writer().create().writeObject(bos, t); | |
} catch (Exception ex) { | |
System.out.println("error serializing traversal: " + ex); | |
} | |
byte[] bytecodeData = bos.toByteArray(); | |
GraphSONReader graphsonReader = graph.io(IoCore.graphson()).reader().create(); | |
Bytecode btcFromJson; | |
try { | |
ByteArrayInputStream bis = new ByteArrayInputStream(bytecodeData); | |
btcFromJson = graphsonReader.readObject(bis, Bytecode.class); | |
bis.close(); | |
bos.close(); | |
} catch (IOException ex) { | |
throw new RuntimeException(ex); | |
} | |
return TraversalBench.<List<?>>runIterations( | |
() -> { | |
if (TIMED_COMPILE) { | |
Bytecode timedJson = graphsonReader.readObject( | |
new ByteArrayInputStream(bytecodeData), Bytecode.class); | |
return JavaTranslator.of(g).translate(timedJson).toList(); | |
} | |
return JavaTranslator.of(g).translate(btcFromJson).toList(); | |
}); | |
} | |
static <V> V runIterations(Callable<V> c) { | |
List<Integer> warmupIterations = new ArrayList<Integer>() {{ add(10); add(100); add(1000); }}; | |
return runMinibench(warmupIterations, c); | |
} | |
private static <V> V runMinibench(List<Integer> warmupIterations, Callable<V> c) { | |
for (Integer iterations : warmupIterations) { | |
long startWarmup = System.nanoTime(); | |
for (int i = 0; i < iterations; i++) { | |
try { | |
c.call(); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
long endWarmup = System.nanoTime(); | |
System.out.println( | |
String.format( | |
"warmup(%d) done in: \n\ttotal: %fms\n\tper iteration: %fms", | |
iterations, | |
(endWarmup - startWarmup) / 1_000_000d, | |
(endWarmup - startWarmup) / iterations.doubleValue() / 1_000_000d)); | |
} | |
V result; | |
long start = System.nanoTime(); | |
try { | |
result = c.call(); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
long end = System.nanoTime(); | |
System.out.println(String.format("result time: %fms", (end - start) / 1_000_000d)); | |
return result; | |
} | |
private static void assertResultsMatch(List<?> r1, List<?> r2, List<?> r3) { | |
if (r1.isEmpty()) { | |
throw new AssertionError("r1 is empty"); | |
} | |
if (r1.size() != r2.size() || r2.size() != r3.size()) { | |
throw new AssertionError("result set count mismatch"); | |
} | |
for (int i = 0; i < r1.size(); i++) { | |
if (!r1.get(i).equals(r2.get(i)) | |
|| !r1.get(i).equals(r3.get(i))) { | |
System.out.println(r1.get(i)); | |
System.out.println(r2.get(i)); | |
System.out.println(r3.get(i)); | |
throw new AssertionError("object mismatch"); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment