/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.compiler.oopath; import java.util.ArrayList; import java.util.List; import org.assertj.core.api.Assertions; import org.drools.compiler.oopath.model.Child; import org.drools.compiler.oopath.model.Man; import org.drools.compiler.oopath.model.Toy; import org.drools.compiler.oopath.model.Woman; import org.drools.core.common.InternalFactHandle; import org.kie.api.KieBase; import org.kie.api.io.ResourceType; import org.kie.api.runtime.KieSession; import org.kie.internal.utils.KieHelper; public class OOPathBenchmarkTest { private static final String RELATIONAL_DRL = "import org.drools.compiler.oopath.model.*;\n" + "global java.util.List list\n" + "\n" + "rule R when\n" + " $man : Man()\n" + " $wife : Woman( husband == $man.name )\n" + " $child : Child( mother == $wife.name, age > 10 )\n" + " $toy : Toy( owner == $child.name )\n" + "then\n" + " list.add( $toy.getName() );\n" + "end\n"; private static final String FROM_DRL = "import org.drools.compiler.oopath.model.*;\n" + "global java.util.List list\n" + "\n" + "rule R when\n" + " $man: Man( $wife: wife )\n" + " $child: Child( age > 10 ) from $wife.children\n" + " $toy: Toy() from $child.toys\n" + "then\n" + " list.add( $toy.getName() );\n" + "end\n"; private static final String OOPATH_DRL = "import org.drools.compiler.oopath.model.*;\n" + "global java.util.List list\n" + "\n" + "rule R when\n" + " Man( $toy: /wife/children[age > 10]/toys )\n" + "then\n" + " list.add( $toy.getName() );\n" + "end\n"; public static void main(String[] args) { int n = 100000; System.out.println("Relational version"); runTest(new RelationalTest(), n); System.out.println("-------------------------------------"); System.out.println("From version"); runTest(new FromTest(), n); System.out.println("-------------------------------------"); System.out.println("OOPath version"); runTest(new OOPathTest(), n); } private static void runTest(Test test, int n) { final KieBase kbase = getKieBase(test.getDrl()); // warmup for (int i = 0; i < 3; i++) { test.runTest(kbase, n); System.gc(); } final BenchmarkResult batch = new BenchmarkResult("Batch"); final BenchmarkResult incremental = new BenchmarkResult("Incremental"); for (int i = 0; i < 10; i++) { long[] result = test.runTest(kbase, n); batch.accumulate(result[0]); incremental.accumulate(result[1]); System.gc(); } System.out.println(batch); System.out.println(incremental); } interface Test { long[] runTest(KieBase kbase, int n); String getDrl(); } private static class RelationalTest implements Test { @Override public long[] runTest(KieBase kbase, int n) { return testRelational(kbase, n); } @Override public String getDrl() { return RELATIONAL_DRL; } } private static class FromTest implements Test { @Override public long[] runTest(KieBase kbase, int n) { return testFrom(kbase, n); } @Override public String getDrl() { return FROM_DRL; } } private static class OOPathTest implements Test { @Override public long[] runTest(KieBase kbase, int n) { return testOOPath(kbase, n); } @Override public String getDrl() { return OOPATH_DRL; } } public static long[] testRelational(KieBase kbase, int n) { final long[] result = new long[2]; final KieSession ksession = kbase.newKieSession(); final List<String> list = new ArrayList<String>(); ksession.setGlobal("list", list); final List<Man> model = generateModel(n); final List<Child> toBeModified = getChildToBeModified(model); long start = System.nanoTime(); final List<InternalFactHandle> fhs = insertFullModel(ksession, model); ksession.fireAllRules(); result[0] = System.nanoTime() - start; list.clear(); start = System.nanoTime(); for (Child child : toBeModified) { child.setAge(11); } for (InternalFactHandle fh : fhs) { ksession.update(fh, fh.getObject()); } ksession.fireAllRules(); result[1] = System.nanoTime() - start; Assertions.assertThat(n).isEqualTo(list.size()); ksession.dispose(); return result; } public static long[] testFrom(KieBase kbase, int n) { final long[] result = new long[2]; final KieSession ksession = kbase.newKieSession(); final List<String> list = new ArrayList<String>(); ksession.setGlobal("list", list); final List<Man> model = generateModel(n); final List<Child> toBeModified = getChildToBeModified(model); long start = System.nanoTime(); final List<InternalFactHandle> fhs = insertModel(ksession, model); ksession.fireAllRules(); result[0] = System.nanoTime() - start; list.clear(); start = System.nanoTime(); for (Child child : toBeModified) { child.setAge(11); } for (InternalFactHandle fh : fhs) { ksession.update(fh, fh.getObject()); } ksession.fireAllRules(); result[1] = System.nanoTime() - start; Assertions.assertThat(n * 3).isEqualTo(list.size()); ksession.dispose(); return result; } public static long[] testOOPath(KieBase kbase, int n) { final long[] result = new long[2]; final KieSession ksession = kbase.newKieSession(); final List<String> list = new ArrayList<String>(); ksession.setGlobal("list", list); final List<Man> model = generateModel(n); final List<Child> toBeModified = getChildToBeModified(model); long start = System.nanoTime(); insertModel(ksession, model); ksession.fireAllRules(); result[0] = System.nanoTime() - start; list.clear(); start = System.nanoTime(); for (Child child : toBeModified) { child.setAge(11); } ksession.fireAllRules(); result[1] = System.nanoTime() - start; Assertions.assertThat(n).isEqualTo(list.size()); ksession.dispose(); return result; } private static KieBase getKieBase(String drl) { return new KieHelper().addContent(drl, ResourceType.DRL).build(); } private static List<Man> generateModel(int nr) { final List<Man> model = new ArrayList<Man>(); for (int i = 0; i < nr; i++) { final Man man = new Man("m" + i, 40); model.add(man); final Woman woman = new Woman("w" + i, 35); man.setWife(woman); woman.setHusband(man.getName()); final Child childA = new Child("cA" + i, 12); woman.addChild(childA); childA.setMother(woman.getName()); final Child childB = new Child("cB" + i, 10); woman.addChild(childB); childB.setMother(woman.getName()); final Toy toyA = new Toy("tA" + i); toyA.setOwner(childA.getName()); childA.addToy(toyA); final Toy toyB = new Toy("tB" + i); toyB.setOwner(childA.getName()); childA.addToy(toyB); final Toy toyC = new Toy("tC" + i); toyC.setOwner(childB.getName()); childB.addToy(toyC); } return model; } private static List<Child> getChildToBeModified(List<Man> model) { final List<Child> toBeModified = new ArrayList<Child>(); for (Man man : model) { for (Child child : man.getWife().getChildren()) { if (child.getAge() == 10) { toBeModified.add(child); } } } return toBeModified; } private static List<InternalFactHandle> insertModel(KieSession ksession, List<Man> model) { final List<InternalFactHandle> fhs = new ArrayList<InternalFactHandle>(); for (Man man : model) { fhs.add((InternalFactHandle)ksession.insert(man)); } return fhs; } private static List<InternalFactHandle> insertFullModel(KieSession ksession, List<Man> model) { final List<InternalFactHandle> toBeModified = new ArrayList<InternalFactHandle>(); for (Man man : model) { ksession.insert(man); ksession.insert(man.getWife()); for (Child child : man.getWife().getChildren()) { final InternalFactHandle fh = (InternalFactHandle)ksession.insert(child); if (child.getAge() == 10) { toBeModified.add(fh); } for (Toy toy : child.getToys()) { ksession.insert(toy); } } } return toBeModified; } public static class BenchmarkResult { private final String name; private long min = Long.MAX_VALUE; private long max = 0; private long sum = 0; private int counter = 0; public BenchmarkResult(String name) { this.name = name; } public void accumulate(long result) { if (result < min) { min = result; } if (result > max) { max = result; } sum += result; counter++; } private long getAverage() { return (sum - min - max) / (counter - 2); } @Override public String toString() { return name + " results: min = " + min + "; max = " + max + "; avg = " + getAverage(); } } }