Hi Jochen,
just a quick feedback: We use distinct classes derived from a Table base
class to model concrete database tables (e.g. PERSON_Table,
DEPARTMENT_Table, ADDRESS_Table, etc), but the different columns in
those tables are not modelled as separate classes, but are just
instances of the same Column class (or one of a few child classes that
represent diffferent types of reference columns), e.g. it looks
something like (actual code uses static imports / helper methods to be
more compact / readable):
class PERSON_Table extends Table {
@Lazy static final PERSON = new PERSON_Table('PERSON','pe')
final ID = new Column(this, 'ID', SqlTypes.ID_DEFAULT, true)
final DEPARTMENT_ID = new TableRefColumn(this,
DEPARTMENT_Table.DEPARTMENT)
final FIRST_NAME = new Column(this, 'FIRST_NAME ',
SqlTypes.VARCHAR(64))
final LAST_NAME = new Column(this, 'LAST_NAME ', SqlTypes.VARCHAR(128))
final DATE_OF_BIRTH = new Column(this, 'DATE_OF_BIRTH ', SqlTypes.DATE)
// ...
}
Cheers,
mg
On 10/05/2022 20:09, Jochen Theodorou wrote:
On 09.05.22 22:13, MG wrote:
Hi Jochen,
our code certainly creates a lot of (short lived) class instances*, but
we do not dynamically create new classes, so the overhead of creating
the initial Indy callsites should only be incurred once at the
beginning, and then should no longer play a role. So if the same SQL
creation code is executed in a loop as in the sample script I provided,
each loop after the first should be as fast as non-Indy Groovy, no ?
You pay the cost every time the callsite gets invalidated. If you do
def getMeta(table, column) {
table.getMetaData(column)
}
getMeta(PERSON, PERSON_NAME)
getMeta(PERSON, PERSON_STREET)
class PERSON extends Table {
...
class PERSON_NAME extends Column {...}
class PERSON_STREET extends Column {...}
...
}
then you have 3 callsites, but 4 inits, since the callsite in getMeta
will be invalidated for the change from PERSON_NAME to PERSON_STREET.
And if you do
10.times {
getMeta(PERSON, PERSON_NAME)
getMeta(PERSON, PERSON_STREET)
}
you get 20 callsite inits plus 19 callsite invalidations in getMetaClass.
Even with caching.. in the current implementation we check only on the
receiver, but here an argument is changing.
If I rerun my test with 1 classes a 1 method and let this run for 500k
times then I get
Groovy 4 indy: 68-73
Groovy 3 non-indy: 90-101
Of course the less iterations the worse for indy:
Groovy 4
1k: 1215
10k: 231
100k: 105
1m: 70
Groovy 3
1k: 780-1000
10k: 169
100k: 96
1m: 90
each run involves running the code 10 times, then measuring 10 times to
really really trying to exclude any initial costs. And from that
perspective Groovy 4 indy is better.
Do you think that a Groovy feature such as e.g. traits could be
responsible for the constant need for callsite creation ? A less-used
Groovy feature such as traits, that we use only in certain, more complex
scenarios, being responsible might explain why the performance problems
a) occur only in more complex test cases, and b) up to date no other
project seems to suffer the same problem as we do...
[...]
I do not remember anymore how they are compiled - but from what I
remember I think there is a level of indirection involved, just don't
remember if that call is in dynamic or static. If the first, then it
might be
bye Jochen