> On Oct 6, 2015, at 4:38 AM, Claes Redestad <claes.redes...@oracle.com> wrote:
> 
> Hi Mandy,
> 
> On 2015-10-05 23:13, Mandy Chung wrote:
>> I have been experimenting a jlink plugin to improve the module system 
>> startup time.   On a Quad-Core Intel Xeon E5 @3.7 GHz, 16G memory (Mac Pro) 
>> machine, the module system startup takes 110 ms and 75% of it is to 
>> reconstitute 64 module descriptors with 2388 packages altogether.
>> 
>> This high overhead includes initializing lambda forms (class loading, 
>> linking, initialization), parsing of module-info.class and compilation of 
>> many methods during startup.
>> 
>> The attached charts shows the summary of module system startup
>> 1) jake-b83 (as of Sep 29)
>>     module bootstrap time            110 ms
>>     module descriptor reconstitution 82 ms
>>     VM startup time is 3x of jdk9-b83 vm startup time (148ms vs 47 ms)
>> 
>> 2) No lambda at startup
>>     module bootstrap time        66 ms  (saved 44 ms compared to #1)
>>     module descriptor reconstitution 33.6 ms (saved 48.4ms)
>>     VM startup time is 2.2x of jdk9-b83 (105ms vs 47ms)
>> 
>> 
>> 3) jlink plugin to generate a .class file to build module descriptors at 
>> link time
>>     module bootstrap time        50.7 ms  (saved 15.3ms compared to #2)
>>     module descriptor reconstitution 16.8 ms (saved 16.8ms)
>>     VM startup time is 1.9x of jdk9-b83 (90ms vs 47ms)
> 
> Is it safe to assume that #3 include the changes in #2?

#2 and #3 are different changes.  ModuleDescriptor.Requires::modsValue is one 
use of lambda that is changed in both #2 and #3.  Other change of 
Stream::forEach in ModuleDescriptor in #2 are not in #3.

#3 has its own builder to create ModuleDescriptor.  Stream::forEach is used in 
3 places in ModuleDescriptor in the loop validating the strings passing in the 
Exports and Provides constructor for example that is skipped in this installed 
module descriptor reconstitution.   

#2 is mainly to measure the overhead due to lambda at startup to help 
understand what attributes to 82ms. 

> 
>> 
>> For #3, it parses module-info.class at link time and validates all names.  
>> It generates a .class file to call a custom Builder to create 
>> ModuleDescriptor for the installed modules.  At runtime, the generated class 
>> will construct the Builder and ModuleDescriptor objects will skip name 
>> validation, no defensive copy of the input set/map and skip reading and 
>> parsing of module-info.class (this is done by a special module descriptor 
>> builder class that doesn’t use lambda.  This special builder is only used by 
>> installed modules).
> 
> Since you're generating and loading classes that would otherwise not be 
> loaded, have you done any footprint measurements?
> 

The charts show the number of loaded classes and heap usage for these 3 runs:
   http://cr.openjdk.java.net/~mchung/jigsaw/jake-startup.20151005.pdf

692 classes are loaded in #1 and 503 classes are loaded in #3.  Heap usage 
after GC in #1 and #3 is 1443 KB 1380 KB respectively.
  
> Alternatively, wouldn't it be possible for the plugin to modify the 
> module-info.class directly?
> 

Yes it’s possible but I don’t see how this can improve the startup time.

>> 
>> It saves 15.3 ms (23% of the module system bootstrap time in #2).   The 
>> downside of this optimization is a little harder to make change and diagnose 
>> (this plugin implementation is straight forward though).   There may be 
>> other small optimization to explore that could be done at jlink time (e.g. 
>> BuiltinClassLoader maintains a package to module map that can be constructed 
>> with a specific size to avoid map resizing).
>> 
>> What’s your thought/opinion to integrate this jlink plugin into jake?
> 
> In general I think improving startup by staving off the first use of lambda 
> isn't very helpful except for trivial applications (which we often 
> over-emphasize when testing startup), while moving module validation to link 
> time seems more like a real gain. It's a bit hard to tell if it's worth it 
> without having seen a patch for the prototype, though.

I hope that LambdaForm initialization can be speed up so that it won’t incur 
significant overhead at startup time.  As I explain above,  
ModuleDescriptor.Requires::modsValue is the only method changed from 
Stream::forEach to foreach loop.

Mandy

Reply via email to