grails/grails-core

Databinding is quite slow when domain implements traits

Opened this issue · 10 comments

We have observed that databinding runs quite slower when domain class implements traits.
I have attached the sample which shows the issue. Databinding runs quite slower (some time even 100% slower) on domains which implements traits.

Given a domain class

class City {
    String name
    String shortCode
    String state
    String country

    BigDecimal latitude
    BigDecimal longitude
}


@CompileStatic
trait CityTrait {
    String name
    String shortCode
    String state
    String country

    BigDecimal latitude
    BigDecimal longitude
}

class CityWithTrait implements CityTrait {
}

Given the City and CityWithTrait domain classes. The databinding the same props on CityWithTrait is quite slower compared to City.

Look at the attached example.
perftest-bug-report-17112017.zip

Create a runnable war, or run with bootrun.

The BootStrap runs the databinding on both of the sample domains for a million times and displays the time taken on console. Notice how slow the databinding on domain with trait it.

Bootstrap also manually sets the properties (using assignments) a 1 million time on both domains. Notice there is no big difference on how much time it takes.

So obviously it databinding which is some how getting affected by traits.

Environment Information

  • Operating System: OSX
  • Grails Version: 3.2.11
  • JDK Version: 1.8

I am curious what could be going on in this case, if there is any hint, i would be glad to investigate / PR.
I tried few things, like if looking up props using reflection is slower on traits, but thats not the case.

Does marking CityWithTrait with @CompileStatic have a noticeable effect?

The linked zip file does not contain a buildable project. Some of the Gradle config is missing.

I have put a buildable version of the project at https://github.com/jeffbrown/issue10862.

you can see the trait slow down benchmark along with some other examples here https://github.com/9ci/grails-gorm-benchmarks

With https://github.com/jeffbrown/issue10862:

Took 12.721 seconds to databind domain City 100000 times
Took 12.396 seconds to databind domain City 100000 times
Took 11.196 seconds to databind domain StaticallyCompiledCity 100000 times
Took 10.791 seconds to databind domain StaticallyCompiledCity 100000 times
Took 19.161 seconds to databind domain CityWithTrait 100000 times
Took 18.954 seconds to databind domain CityWithTrait 100000 times
Took 16.75 seconds to databind domain StaticallyCompiledCityWithTrait 100000 times
Took 17.056 seconds to databind domain StaticallyCompiledCityWithTrait 100000 times
Took 1.303 seconds to manually set props on domain City 100000 times
Took 0.456 seconds to manually set props on domain StaticallyCompiledCity 100000 times
Took 1.372 seconds to manually set props on domain CityWithTrait 100000 times
Took 0.551 seconds to manually set props on domain StaticallyCompiledCityWithTrait 100000 times

The class at https://github.com/jeffbrown/issue10862/blob/50dc2bb070df7951865bdf2a81adb6b52d0a77b9/grails-app/domain/bugwork/CityWithNonFieldProperties.groovy demonstrates that the issue isn't really with traits per se but the way that property access works. Note that CityWithNonFieldProperties performs about the same as CityWithTrait.

Took 13.641 seconds to databind domain City 100000 times
Took 13.09 seconds to databind domain City 100000 times
Took 18.393 seconds to databind domain CityWithNonFieldProperties 100000 times
Took 19.077 seconds to databind domain CityWithNonFieldProperties 100000 times
Took 19.159 seconds to databind domain CityWithTrait 100000 times
Took 19.17 seconds to databind domain CityWithTrait 100000 times
Took 11.173 seconds to databind domain StaticallyCompiledCity 100000 times
Took 13.498 seconds to databind domain StaticallyCompiledCity 100000 times
Took 17.302 seconds to databind domain StaticallyCompiledCityWithNonFieldProperties 100000 times
Took 17.604 seconds to databind domain StaticallyCompiledCityWithNonFieldProperties 100000 times
Took 18.208 seconds to databind domain StaticallyCompiledCityWithTrait 100000 times
Took 19.212 seconds to databind domain StaticallyCompiledCityWithTrait 100000 times
Took 1.425 seconds to manually set props on domain City 100000 times
Took 1.426 seconds to manually set props on domain CityWithNonFieldProperties 100000 times
Took 1.581 seconds to manually set props on domain CityWithTrait 100000 times
Took 0.403 seconds to manually set props on domain StaticallyCompiledCity 100000 times
Took 0.42 seconds to manually set props on domain StaticallyCompiledCityWithNonFieldProperties 100000 times
Took 0.53 seconds to manually set props on domain StaticallyCompiledCityWithTrait 100000 times

Interesting, just curious, @jeffbrown any idea why would it take longer non field properties ?

When i tried, the dynamic lookup and setting value on property using MetaProperty dint have much difference in time it took, regardless if it is properties without fields.

Interesting, just curious, @jeffbrown any idea why would it take longer non field properties ?

No. Would need to profile it and figure out where the time is being spent.

@ilopmar whats the workaround for Databind slowness issue? It takes almost 5-10seconds to databind object in our case. Please let me know if any resolution available in Grails 3.2.11