My rule brings OH to CPU usage >100%

OK, I misunderstood, I thought the delay you were reporting was the runtime of the rule. I can confirm with this specific Rule I’m seeing about a 3 minute load time with near 100% CPU on a 2 virtual cpu VM.

And it does totally stack up. If you don’t wait for the rule to be loaded and make additional edits you will be sitting at 100% CPU utilization for a good long time.

This is really good as it gives the maintainers a Rule they can use on just about any machine (it would appear) to reproduce the behavior. Do we know if there has been an issue opened and what it is? I assume this would be in core.

I tend to agree about deprecating Rules DSL but I suspect it’s going to be a long process to make that happen. If this can be fixed it should probably be fixed.

No. You don’t have to import anything from java.lang. When I copied Scott’s version of the Rule I left the import out and it took forever to load with a very high load.

I decided to do a quick test and I think I know why your version doesn’t have the problem but OP’s and Scotts does. When I take the crazy long calculation and break it up into multiple lines, saving the results of smaller pieces of the calculation to a variable like in your Rule the loading problem goes away, or at least is way less noticeable (a few seconds as opposed to three minutes).

rule "Test"
when
    System started
then
    logWarn("Rules", "Test: Start")
    val a = 243.5
    val b = Math::log((vBasement_Light.state as Number).doubleValue / 100)
    val c = (17.67 * (vBasement_Light.state as Number).floatValue())
    val d = (243.5 + (vBasement_Light.state as Number).floatValue())
    val e = 17.67 - Math::log((vBasement_Light.state as Number).floatValue / 100)
    val f = 17.67 * (vBasement_Light.state as Number).floatValue()
    val g = 243.5 + (vBasement_Light.state as Number).floatValue()

    val Taupunkt = a * (b + (c/d)) / (e - (f / g))

//    val Taupunkt = 243.5 * (Math::log((Virtual_Number_1.state / 100)) + ((17.67 * Current_Temperature.state.floatValue())/(243.5 + Current_Temperature.state.floatValue()))) / (17.67 - Math::log(Virtual_Number_1.state / 100) - (17.67 * Current_Temperature.state.floatValue() / (243.5 + Current_Temperature.state.floatValue())))
    logWarn("Rules", "Value = {}", Taupunkt)

    logWarn("Rules", "Test: End")
end

I have no idea if I have the parens in the right place in my conversion but that isn’t the point. I’m not testing for the correct answer, just to see how the parser handles the calculations. And I just some random Number Item in place of the number Items from the original calculations. I just need a number, I’m not after verifying the actual result.

The above Rule took about 5 seconds to load. And it has just as many primitives and just as many calculations as the original. It just doesn’t try to do it all on one line of code.

I suspect that the part of the Rules Parser that checks type at parse time is O(N!) or O(C^N) or something crazy like that (I know, only CS type folks will understand what that means, see Big O notation - Wikipedia for details) meaning the more stuff you give it to have to try and figure out type on one line the amount of work required goes through the roof. The problem with using primitives is that the Rules DSL can’t delay the type checking until runtime like it can with Objects so we are forcing it to go down this O(N!) O(C^N) algorithm.

So my recommendation is:

  • Avoid using primitives unless absolutely necessary (e.g. passing them to a method that requires a primitive)
  • Do not convert values to primitives until the absolutely last moment (e.g. keep it as a Number until you actually make the call that requires it to be a primitive)
  • Break up long calculations into multiple lines. Not only is this easier to read, it lowers the value of N for those lines making the job much easier on the parser to verify the types for the lines that use primitives.
  • Don’t edit Rules DSL files in place or at least watch the logs to make sure your previous edits were loaded before making and new saves.
    EDIT:
  • Consider moving to Scripted Automation which does not have this and other problems exhibited by Rules DSL
3 Likes