I will read PEP 649 implementation to find missing optimizations other than GH-25419 and GH-23056.
I found each "__co_annotation__" has own name like "func0.__co_annotation__". It increased pyc size a little. I created a draft pull request for cherry-picking GH-25419 and GH-23056 and using just "__co_annotation__" as a name. https://github.com/larryhastings/co_annotations/pull/9/commits/48a99e0aafa2d...
``` # previous result $ ./python ~/ann_test.py 3 code size: 204963 bytes memory: 209257 bytes unmarshal: avg: 587.336ms +/-2.073ms exec: avg: 97.056ms +/-0.046ms
# Use single name $ ./python ~/ann_test.py 3 code size: 182088 bytes memory: 209257 bytes unmarshal: avg: 539.841ms +/-0.227ms exec: avg: 98.351ms +/-0.064ms ```
It reduced code size and unmarshal time by 10%. I confirmed GH-25419 and GH-23056 works very well. All same constants are shared.
Unmarshal time is still slow. It is caused by unmarshaling code object. But I don't know where is the bottleneck: parsing marshal file, or creating code object.
Then, I tried to measure method annotation overhead. Code: https://gist.github.com/methane/abb509e5f781cc4a103cc450e1e7925d#file-ann_te... Result:
``` # No annotation $ ./python ~/ann_test_method.py 0 code size: 113019 bytes memory: 256008 bytes unmarshal: avg: 336.665ms +/-6.185ms exec: avg: 176.791ms +/-3.067ms
# PEP 563 $ ./python ~/ann_test_method.py 2 code size: 120532 bytes memory: 269004 bytes unmarshal: avg: 348.285ms +/-0.102ms exec: avg: 176.933ms +/-4.343ms
# PEP 649 (all optimization included) $ ./python ~/ann_test_method.py 3 code size: 196135 bytes memory: 436565 bytes unmarshal: avg: 579.680ms +/-0.147ms exec: avg: 259.781ms +/-7.087ms ```
PEP 563 vs 649 * code size: +63% * memory: +62% * import time: +60%
PEP 649 annotation overhead (compared with no annotation): * code size: +83 byte/method * memory: +180 byte/method * import time: +326 us/method
It is disappointing because having thousands methods is very common for web applications.
Unlike simple function case, PEP 649 creates function object instead of code object for __co_annotation__ of methods. It cause this overhead. Can we avoid creating functions for each annotation?