Red Hat Bugzilla – Bug 981410
Perf. regression when using rules with collect
Last modified: 2014-08-06 16:20:04 EDT
Description of problem:
Evaluating simple rules with accumulate and collect takes longer with 6.0.0-SNAPSHOT, comparing to 5.3.1-P03. Rules have only "when" part, "then" in empty.
The rules look like this:
$account : Account(uuid == "transactionsWithCertainAccountFrom_collect_100000")
$transactions : ArrayList(size >= 2)
from collect (Transaction(accountFrom == $account))
$totalBalance : Number ()
from accumulate (Account($balance : balance, uuid == "totalAverageMinMaxlBalanceForCertainAccounts_accumulate_100000"),
init(double total = 0;),
action(total += $balance;),
reverse(total -= $balance;),
The difference depends on number of rules, facts, activations, etc, but is about 10% - 30%.
See attached Maven reproducer for more details.
Version-Release number of selected component (if applicable):
6.0.0-SNAPSHOT (and also beta4)
Steps to Reproduce:
1. Run the attached reproducer for drools5 and drools6 (mvn test)
2. Compare the results printed to stdout
Significant difference between the execution time for drools5 and drools6
Execution time is ~same for both drools5 and drools6
Created attachment 768859 [details]
Maven based reproducer
I will try to look more closely into this and find out what construct/operator is causing the regression.
Created attachment 770538 [details]
Reproducer with only 'collect' rules enabled
I have divided the test in two - one using only 'accumulate' and one only 'collect'. Running them and comparing the execution times with Drools 5, it _seems_ that the problem is caused by 'collect' only, because the 'accumulate' test is taking ~same time on both Drools 5 and Drools 6.
I have also updated the reproducer with the those two tests where one is using only accumulate and one only collect. By default only the one with collect is enabled, to its enough to run "mvn test" on both modules (drools5 and drools6) to see the difference.
Running the provided test case I actually found that 5.3.x is around 20% faster than 6.0.x on my machine in that specific case (2600ms Vs. 3200ms).
Using the profiler I found that one of the causes of this difference was the excessive resizing of the HashTable implementing both the Right and Left TupleMemory. However phreak allows me to know in advance how many tuples I am going to add to a memory so I tried to ensure of having enough space in the HashTable before of starting adding them. I implemented this optimization here
and it allowed me to half the difference with the 5.3.x bringing the execution time of the test case on the 6.0.x from 3200 to 2900 ms.
For the rest it is hard to compare the 5.3.x and the 6.0.x, but the biggest difference I can see at the moment is in the constructor of the RightTuple that takes the 15.0% of the total execution time on the 6.0.x and only the 3.2% on the 5.3.x. In particular this difference is caused by the new DefaultFactHandle.addRightTupleInPosition method invoked in the RightTuple constructor. Despite this method looks quite trivial, evidently it becomes relevant when invoked millions of times as it happens in that test and anyway I think that what it does is nor avoidable neither further improvable.
I have done some preliminary testing and there definitely is an improvement around 10 %. There is still some regression but as Mario pointed out, not sure if we can do something about that.
Verified fixed in 6.0.0-ER4. I am not seeing the regression anymore (running the provided test case).