checkParameterIsNotNull taking up 15% of CPU?


#1

I was playing with JProfiler evaluation version, and was a bit surprised to see that after my expected CPU-heavy functions, third place “hotspot” were calls to

15.1% - 35,276 ms - 464,945,919 hot spot inv. kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull

That is… way bigger than I thought it would be. Granted, I’ve got a tight loop that is checking the distance^2 between 2D points over and over, and I haven’t done any sort of sane distance-bucketing to speed it up yet, but still, 15% seemed like a lot.

Cost of doing business? Is this something that could be optimized out? Is there some annotation I could add that indicates “Check if this is null at the beginning for the first few thousand calls, then relax a bit and don’t check every single time.”


#2

Could you provide your testing code?
Are you using Kotlin only code or calling some Java methods?

I don’t think to change the behavior after X number of previous usage is a big gender and I doubt JetBrain will ever do that (not that they should).


#3

As far as I know kotlin adds a call to Intrinsics.checkParameterIsNotNull for each not null parameter of a public functions. Still if you take a look at the kotlin source this function just performs a simple null check.
There are a few ways you could try to reduce calls to this. I don’t know of any internal annotation which would allow you to skip this call but you can change your function.
One way would be to make the critical functions private. That way the compiler knows that it does not have to generate the checks. Not sure if this is possible in your case. You might also try inlining some functions as the intrinsic checks are not inlined (at least not in my simple test).

checkParameterIsNotNull source

https://github.com/JetBrains/kotlin/blob/ba6da7c40a6cc502508faf6e04fa105b96bc7777/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/Intrinsics.java#L114

public static void checkParameterIsNotNull(Object value, String paramName) {
        if (value == null) {
            throwParameterIsNullException(paramName);
        }
    }

#4

Make sense as public methods can be called from Java and cannot guarantee they are not null.

It would be nice if compiler would create 2 versions of the method:

  • without checks to be used to call from Kotlin code (compiler can reason values are not null)
  • with check to be called from Java, which after checking call the first one

Something like:

inline fun funParams(obj: Any?, str: String?) {
    println("nullableParams: $obj, $str")
    funParams(obj ?: Unit, str ?: "")
}

fun funParams(obj: Any, str: String) {
    println("nullableParams: $obj, $str")
}

The first one can be called from Java, but second – only from Kotlin (without check).

This cannot be done by hands as both funs has the same JVM signature.


#5

There is a compiler option to disable the generation of these checks. More importantly though, you should be very careful with false measurements. In particular the expectation is that this will mostly be optimized out by hotspot. Try to have a version with and a version without and compare their actual performance (without distorting it through a profiler). Similarly what kind of profiling are you using?


#6

I was using the new built-in IntelliJ profiler.