davydotcom opened a new pull request, #15109:
URL: https://github.com/apache/grails-core/pull/15109

   I have been asked to take a look at Grails GSP Performance. This is an older 
codebase and I was able to identify some low hanging fruit to start this 
journey that is pretty safe for release.
   
   There are multiple parts that need to be considered with GSP performance. 
The differences in cold start performance in development mode as well as 
production mode rendering.
   
   Cold start involves compiler overhead. This means any changes in groovy4 
compiler performance @paulk-asert can have a significant impact in this area. 
Fortunately, from what I can tell, there does not seem to be a huge difference 
in performance here in my testing.
   
   I am aware that the compiler (since groovy 3) runs slower on LARGE files. In 
an effort to reduce file size, I have shorthanded `printHtmlParts(Integer)` to 
`h(Integer)` when the gsp is first being converted to a `groovy` file. This 
should help with just scanning and size for the compilation process.
   
   I have also started swapping out commons logging with `SLF4J`. Why you may 
ask? There are several spots where there are wrapped if statements if 
`debugEnabled`. This is no longer necessary on `SLF4J` and simply reads better.
   
   I also have started adding javadoc headers to some of the GSP classes so it 
is easier to follow what is going on in the code. As this is not the easiest to 
read through.
   
   ## Big Optimizations
   
   Whenever a page or partial is rendered, a new instance of `GroovyPage` is 
created. This is never cached even though 99% of the class is thread safe 
(except for the OutputStack). We have made changes in the already cached 
`GroovyPageMetaInfo` class that now instantiates a `ThreadLocal` cache of the 
page. In addition, the `Constructor` pointer is also cached for concurrent 
access to reduce reflection overhead. There is an excessive amount of 
operations that are performed before a page is rendered in the 
`GroovyPage#initRun()`. I have moved some of this out into `initCommonRun()` 
that only needs to be run per instance, as opposed to per execution of the 
pages `run()`. This can be taken farther by a lot but did not want to create 
high risk issues to start. The other big move was to create the `htmlPartsSet` 
in the meta info class instead of during construction of each groovy page 
instance.
   
   Making this change shows approximately 30% in overhead reduction.
   
   ### Test Scenarios
   
   **First Scenario: Render 10,000 nested template renders in a `<g:each>` of a 
row:**
   
   Render Time after a few warmups BEFORE Changes: 200ms avg
   Render Time after a few warmups AFTER Changes: 150ms avg
   
   **Second Scenario: Render 10,000 nested template renders using `<g:render 
collection=''>`**
   Render Time after a few warmups BEFORE Changes: 63ms avg
   Render Time after a few warmups AFTER Changes: 40ms avg
   
   **Third Scenario: Render LARGE HTML Page (lots of html parts)**
   
   Render Time after a few warmups BEFORE Changes: 2ms avg
   Render Time after a few warmups AFTER Changes: 1ms avg 
   
   These Tests were run on an M3 Max Macbook Pro . I would imagine even more 
gains on different hardware.
   
   
   ### What's next.
   
   We need to aim to further reduce the instantiation logic within `GroovyPage` 
it's a short lived object that needs to be super quick to instantiate. There 
are common singleton reference classes that are associated at the start like 
`TagLibraryLookup` that should be removed.
   
   We need to shorten this pipeline overall. There are a lot more spots I can 
see that need optimized and will continue to dig farther. The TagLibraryLookup 
could also stand a rethink, but that is for another day.
   
   I would appreciate any thoughts on this PR and look forward to hearing if 
this improves overall performance for others.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to