Jess - Performance regression from Java 11 to Java 13+
Asked Answered
P

1

5

we are using Jess, which is a rules engine, written in Java. It has become pretty old and most of it is written using Java 1.5 and lower language features. Now, we are using this for many years and never noticed any problems during the Java upgrades, until now, when we plan to switch from Java 11 to Java 17.

Our runtime has become 30-40% slower, just by switching the java version. We did a lot of testing already, but cannot really find the one culprit.
For instance, we checked different Java versions and different vendors (eclipse, azul and orcacle), everything from 13+ was slower than Java 11.

Using VisualVM I was able to point down to a few methods, but there is nothing specific in there where I would say that this could be the problem.
Looking at it, it seems like there are multiple performance regressions that sum together to a big one, but that seems pretty unrealistic.

Some of the functions look like this:

    private synchronized Map findVariable(String key) {
        Context c = this;
        while (c != null) {
            Map ht = c.getVariables();
            Value v = (Value) ht.get(key);
            if (v != null)
                return ht;
            else
                c = c.m_parent;
        }
        return null;
    }

    private synchronized Map getVariables() {
        if (m_variables == null)
            m_variables = Collections.synchronizedMap(new HashMap());

        return m_variables;
    }

Do you know if there are any know regressions going on from J13+, maybe regarding synchronized functions and variables for instances?

Any other pointers what might be the problem?

Panamerican answered 2/2, 2023 at 14:18 Comment(9)
You're still using raw types? Interesting, but unrelated to your performance. I don't know anything about this regression. Since you plan to move to 17 anyway, did you check if maybe it's fixed again in 17?Benedikta
Is there any bench marking(e.g. jmh) to let us verify?Daigle
@JoachimSauer We bought the library and it's code, we don't want to change it unless it's really necessary, so yea, it's still the old code from almost 2 decades ago. Java 17 has the same performance problems, unfortunately.Panamerican
@Daigle We only have raw numbers from our internal testing tools, not sure if that's of any help. I can setup a test project and bench with jmh if that helps in any way?Panamerican
@sveri: I mean if you could boil it down to a reasonably small minimal reproducible example then that would of course help (both for this question and your own hunt for a solution), but if it's really as you said that it's just many small regressions, then this might be tricky. Personally I'd still try it for a while to see if you find an "easy" culprit.Benedikta
@Panamerican have you tried to re-enable biased locking? I believe <=1.5 code is full of StringBuffers, Vectors, HashTables, etcMarriageable
@AndreyB.Panfilov: oh, that's a good hint. Collections.synchronizedMap probably produces lots of uncontested locking attempts. If re-enabling biased locking helps, then replacing those with ConcurrentHashMaps would probably help as well. (edit: oh, but "Prior to JDK 15, biased locking is always enabled").Benedikta
@AndreyB.Panfilov You are my man, I just ran the test code with reenabled biased locking and Java 17 and the numbers are even a bit better than with Java 11. Awesome, if you provide this as answer, I will accept it.Panamerican
Just because you paid for it, doesn’t make it code worth keeping. It’s poor code, even by the old standards 1.) pointless lazy initialization, far more expensive than its supposed savings 2) overuse of synchronization, 3) no-idiomatic test for the presence of a key; instead of Value v = (Value) ht.get(key); if (v != null) return ht;, you can just use if(ht.containsKey(key)) return ht; 4) non-idiomatic loop. What you have here, is a classical for loop: for(Context c = this; c != null; c = c.m_parent) { Map ht = c.getVariables(); if(ht.containsKey(key)) return ht; } return null;Barberabarberry
M
7

Based on the fact the library you are using was written for Java 1.5, that time we were primarily using synchronized keyword to write thread-safe code, I would say the root cause of performance degradation you are observing now is JEP 374: Deprecate and Disable Biased Locking

Marriageable answered 2/2, 2023 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.