Can you share the benchmark code? Maybe C2 profiled class hierarchy,
determined your optional only has 2 subclasses and can thus generate
optimized machine code. Or maybe your benchmark is wrong that the result is
not consumed by blackhole so the whole benchmark is moot. We need the code
to make a verdict.

Chen

On Mon, Aug 28, 2023 at 6:27 PM Oleksii Kucheruk <iselo+open...@raccoons.co>
wrote:

> Thank you Quân.
>
> All  you saying guys make sense.
> Yes there is a difference calling methods by pointer and involving vtable.
> But one thing didn't came out of my head:
> If virtual dispatch dispatch is 10-time more expensive and polymorphism is
> a performance killer so how combinations of "return optional - isPresent-
> get" or "return empty - isEmpty" with virtual dispatch and memory
> allocation for every empty or sole but polymorph empty could perform
> equally or even beat the near zero-cost abstraction of Value classes
> according to JMH?
>
> Maybe private final static nested EmptyOptional invokevirtual bytecode refers
> a final methods and it need not have a vtable slot allocated. This means
> that, after linking, an invokevirtual bytecode might in fact collapse into
> the equivalent of an invokestatic bytecode.
> The question of full dynamic with anonymous overloading is still unclear
> to me.
>
> Benchmark                                               Mode  Cnt
>   Score           Error  Units
>
> *OptionalComboIsPresentGet.opDynamicAnonymous           thrpt   30
> 1059868995.937 ±  51273067.116  ops/s*
>
> OptionalComboIsPresentGet.opJdk                        thrpt   30  
> 1017505800.567
> ±  16007847.872  ops/s
>
> OptionalComboIsPresentGet.opNestedStatic               thrpt   30   
> 951493332.957
> ±  12167812.398  ops/s
>
>
> OptionalComboOfIsPresentGetTest.opDynamicAnonymous     thrpt   30  
> 1426348334.485
> ±  20889455.433  ops/s
>
> *OptionalComboOfIsPresentGetTest.opJdk                  thrpt   30
> 1435570789.822 ±  16587538.659  ops/s*
>
> OptionalComboOfIsPresentGetTest.opNestedStatic         thrpt   30  
> 1418853644.215
> ±  27755398.645  ops/s
>
>
> *OptionalComboOfNullableIsEmptyTest.opDynamicAnonymous  thrpt   30
> 1434399595.592 ±  14749443.903  ops/s*
>
> OptionalComboOfNullableIsEmptyTest.opJdk               thrpt   30  
> 1255375023.531
> ± 107403119.573  ops/s
>
> OptionalComboOfNullableIsEmptyTest.opNestedStatic      thrpt   30  
> 1415705702.964
> ±  26328318.672  ops/s
>
>
> OptionalEmptyTest.opDynamicAnonymous                   thrpt   30  
> 1417895521.763
> ±  26311640.557  ops/s
>
> *OptionalEmptyTest.opJdk                                thrpt   30
> 1423940087.962 ±  18515297.860  ops/s*
>
> OptionalEmptyTest.opNestedStatic                       thrpt   30  
> 1424779162.084
> ±  20288793.337  ops/s
>
>
> OptionalGetTest.emDynamicAnonymous                     thrpt   30      
> 569132.235
> ±     11089.903  ops/s
>
> *OptionalGetTest.emJdk                                  thrpt   30
> 549764.038 ±     14768.566  ops/s*
>
> OptionalGetTest.emNestedStatic                         thrpt   30      
> 568308.722
> ±      6075.671  ops/s
>
>
> OptionalGetTest.opDynamicAnonymous                     thrpt   30   
> 953788065.414
> ±   7043419.784  ops/s
>
> *OptionalGetTest.opJdk                                  thrpt   30
> 1015679232.049 ±  11726562.032  ops/s*
>
> OptionalGetTest.opNestedStatic                         thrpt   30   
> 944209513.151
> ±  17718342.519  ops/s
>
>
> OptionalIsPresentTest.emDynamicAnonymous               thrpt   30   
> 869086292.481
> ±  11668636.886  ops/s
>
> *OptionalIsPresentTest.emJdk                            thrpt   30
> 977042244.447 ±  44558020.220  ops/s*
>
> OptionalIsPresentTest.emNestedStatic                   thrpt   30   
> 953424664.631
> ±   8448564.963  ops/s
>
>
> OptionalIsPresentTest.opDynamicAnonymous               thrpt   30   
> 953285872.799
> ±   6562894.941  ops/s
>
> *OptionalIsPresentTest.opJdk                            thrpt   30
> 1006926903.885 ±  18055487.689  ops/s*
>
> OptionalIsPresentTest.opNestedStatic                   thrpt   30   
> 954121471.431
> ±   6829528.708  ops/s
>
>
> OptionalOfNullableTest.emDynamicAnonymous              thrpt   30  
> 1422939780.266
> ±  21693247.354  ops/s
>
> *OptionalOfNullableTest.emJdk                           thrpt   30
> 1423340184.237 ±  21296444.017  ops/s*
>
> OptionalOfNullableTest.emNestedStatic                  thrpt   30  
> 1414965236.385
> ±  26021734.344  ops/s
>
>
> OptionalOfNullableTest.opDynamicAnonymous              thrpt   30  
> 1412594454.538
> ±  28123612.298  ops/s
>
> *OptionalOfNullableTest.opJdk                           thrpt   30
> 1427924599.589 ±  23469517.835  ops/s*
>
> OptionalOfNullableTest.opNestedStatic                  thrpt   30  
> 1420053175.637
> ±  21170929.571  ops/s
>
>
> OptionalOfTest.emDynamicAnonymous                      thrpt   30      
> 549907.559
> ±     14560.954  ops/s
>
> OptionalOfTest.emJdk                                   thrpt   30      
> 557858.903
> ±      2851.076  ops/s
>
> *OptionalOfTest.emNestedStatic                          thrpt   30
> 548655.854 ±     10875.674  ops/s*
>
>
> OptionalOfTest.opDynamicAnonymous                      thrpt   30  
> 1411307270.435
> ±  19832207.408  ops/s
>
> OptionalOfTest.opJdk                                   thrpt   30  
> 1400651442.726
> ±  23641065.234  ops/s
>
> *OptionalOfTest.opNestedStatic                          thrpt   30
> 1433953744.298 ±  21414147.936  ops/s*
>
>
> On Mon, Aug 28, 2023 at 11:13 AM Quân Anh Mai <anh...@gmail.com> wrote:
>
>> Hi,
>>
>> Polymorphism is a performance killer. Normally this does not matter much,
>> but for thin wrappers such as Optional, this is one of the most important
>> factor.
>>
>> Behaviour polymorphism requires virtual dispatch and prevents inlining.
>> This is really detrimental, as simple operations such as a getter which is
>> previously only consisted of a memory load, in the presence of polymorphism
>> would have to go through a 10-time more expensive virtual dispatch.
>> Function calls, especially virtual ones, are also opaque and prohibit
>> compiler optimisations.
>>
>> Layout polymorphism prevents direct accesses and requires indirection.
>> This means that for every instance of Optional created a memory allocation
>> is required. Optional is expected to be a near zero-cost abstraction in the
>> presence of Value classes, so making it polymorphic is unacceptable.
>>
>> Thanks.
>>
>> On Wed, 23 Aug 2023 at 22:43, Oleksii Kucheruk <iselo+open...@raccoons.co>
>> wrote:
>>
>>> Hi there.
>>> I have found that `java.util.Optional` is written procedural style and
>>> has `ifnonnull`  checks in each method. I propose to refactor `Optional` in
>>> accordance to OOP-style. This will eliminates all unnecessary
>>> `if`-statements, removes duplications and reduces bytecode size more then
>>> twice.
>>>
>>> I have two solutions:
>>> 1. Completely dynamic that avoids single static `EMPTY` instance and
>>> unchecked casting of each `Optional.empty()`
>>> 2. Preserving original single static `EMPTY` per VM.
>>>
>>> Also there are couple methods that throws NPE due to calling methods on
>>> null-objects and requires to add `Objects.requireNonNull(...)`.
>>>
>>> OptionalInt, OptionalDouble, OptionalLong could be refactored same way
>>> even with remove of additional boolean variable `isPresent`.
>>>
>>> Since I'm new here any guidance will be helpful.
>>> Thank you in advance.
>>>
>>

Reply via email to