Skip to content

gh-132042: Try to optimize class creation #132156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

sergey-miryanov
Copy link
Contributor

@sergey-miryanov sergey-miryanov commented Apr 6, 2025

@python-cla-bot
Copy link

python-cla-bot bot commented Apr 6, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@StanFromIreland
Copy link
Contributor

Maybe take a look at this comment and have it in mind.

@sergey-miryanov
Copy link
Contributor Author

@StanFromIreland Yeah, thanks! I just checked both scripts - and timing closely same. But I not finished main task, so results can changed.

@AA-Turner AA-Turner added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Apr 7, 2025
@sergey-miryanov
Copy link
Contributor Author

sergey-miryanov commented Apr 9, 2025

Intermediate results:

Running Release|x64 interpreter...
Python 3.14.0a6+ (heads/gh-132042-optimize-class-creation:b0ad8754b45, Apr  9 2025, 11:38:25) [MSC v.1943 64 bit (AMD64)]

+----------------------------------------------------------------------------+---------+-----------------------+
| Benchmark                                                                  | ref     | new                   |
+============================================================================+=========+=======================+
| empty_cls-1000                                                             | 4.32 ms | 3.50 ms: 1.24x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_dunders-1000                                                      | 5.03 ms | 4.32 ms: 1.16x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-1000-A, B                                             | 5.62 ms | 3.89 ms: 1.45x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-1000-A, B                                                   | 6.18 ms | 4.62 ms: 1.34x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-1000-A, B, D                                          | 6.37 ms | 4.18 ms: 1.52x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-1000-A, B, D                                                | 6.81 ms | 4.92 ms: 1.39x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-1000-A_with_dunders, B_with_dunders                   | 5.40 ms | 3.89 ms: 1.39x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-1000-A_with_dunders, B_with_dunders                         | 6.08 ms | 4.66 ms: 1.31x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-1000-A_with_dunders, B_with_dunders, D_with_dunders   | 6.08 ms | 4.24 ms: 1.44x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-1000-A_with_dunders, B_with_dunders, D_with_dunders         | 6.79 ms | 5.01 ms: 1.36x faster |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls-100000                                                           | 436 ms  | 356 ms: 1.23x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_dunders-100000                                                    | 500 ms  | 434 ms: 1.15x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-100000-A, B                                           | 563 ms  | 387 ms: 1.46x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-100000-A, B                                                 | 612 ms  | 463 ms: 1.32x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-100000-A, B, D                                        | 631 ms  | 418 ms: 1.51x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-100000-A, B, D                                              | 683 ms  | 493 ms: 1.39x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-100000-A_with_dunders, B_with_dunders                 | 545 ms  | 389 ms: 1.40x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-100000-A_with_dunders, B_with_dunders                       | 607 ms  | 467 ms: 1.30x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| empty_cls_with_bases-100000-A_with_dunders, B_with_dunders, D_with_dunders | 609 ms  | 423 ms: 1.44x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| cls_with_bases-100000-A_with_dunders, B_with_dunders, D_with_dunders       | 679 ms  | 502 ms: 1.35x faster  |
+----------------------------------------------------------------------------+---------+-----------------------+
| Geometric mean                                                             | (ref)   | 1.35x faster          |
+----------------------------------------------------------------------------+---------+-----------------------+

b.txt

@sergey-miryanov
Copy link
Contributor Author

sergey-miryanov commented Apr 9, 2025

I added tests from gh-76527 (script for testing with pyperf b.txt):

  • empty_cls - tests for classes without any methods
  • cls - tests for classes with few dunder methods
  • bases - with suffix _dun - base classes with few dunder methods
+---------------------------------------------------------------+----------+-----------------------+
| Benchmark                                                     | ref      | new                   |
+===============================================================+==========+=======================+
| 1000-empty_cls                                                | 4.42 ms  | 3.50 ms: 1.26x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_dunders                                         | 5.25 ms  | 4.45 ms: 1.18x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A', 'B']                    | 5.70 ms  | 3.84 ms: 1.48x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['A', 'B']                          | 6.26 ms  | 4.62 ms: 1.35x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A', 'B', 'D']               | 6.49 ms  | 4.16 ms: 1.56x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['A', 'B', 'D']                     | 6.97 ms  | 4.94 ms: 1.41x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A_dun', 'B_dun']            | 5.52 ms  | 3.89 ms: 1.42x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['A_dun', 'B_dun']                  | 6.21 ms  | 4.67 ms: 1.33x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun']   | 6.20 ms  | 4.20 ms: 1.47x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun']         | 7.10 ms  | 5.02 ms: 1.42x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['Logger']                    | 5.42 ms  | 4.22 ms: 1.28x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['Logger']                          | 6.05 ms  | 5.08 ms: 1.19x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['DatagramHandler']           | 6.63 ms  | 4.42 ms: 1.50x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['DatagramHandler']                 | 7.23 ms  | 5.24 ms: 1.38x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['MagicMock']                 | 7.66 ms  | 4.95 ms: 1.55x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['MagicMock']                       | 8.26 ms  | 5.74 ms: 1.44x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['Shelf']                     | 9.46 ms  | 6.86 ms: 1.38x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['Shelf']                           | 10.2 ms  | 7.84 ms: 1.30x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['tuple']                     | 5.62 ms  | 4.18 ms: 1.35x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['tuple']                           | 6.33 ms  | 5.53 ms: 1.14x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['dict']                      | 5.60 ms  | 4.90 ms: 1.14x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['dict']                            | 6.30 ms  | 5.56 ms: 1.13x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-empty_cls_with_bases-bases=['list']                      | 5.99 ms  | 4.74 ms: 1.26x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 1000-cls_with_bases-bases=['list']                            | 6.68 ms  | 5.64 ms: 1.19x faster |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls                                              | 447 ms   | 354 ms: 1.26x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_dunders                                       | 510 ms   | 436 ms: 1.17x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['A', 'B']                  | 569 ms   | 392 ms: 1.45x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['A', 'B']                        | 631 ms   | 470 ms: 1.34x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['A', 'B', 'D']             | 644 ms   | 416 ms: 1.55x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['A', 'B', 'D']                   | 702 ms   | 499 ms: 1.41x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['A_dun', 'B_dun']          | 550 ms   | 387 ms: 1.42x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['A_dun', 'B_dun']                | 627 ms   | 474 ms: 1.32x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun'] | 621 ms   | 422 ms: 1.47x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun']       | 694 ms   | 509 ms: 1.36x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['Logger']                  | 540 ms   | 418 ms: 1.29x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['Logger']                        | 612 ms   | 508 ms: 1.20x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['DatagramHandler']         | 657 ms   | 441 ms: 1.49x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['DatagramHandler']               | 726 ms   | 530 ms: 1.37x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['MagicMock']               | 764 ms   | 492 ms: 1.55x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['MagicMock']                     | 828 ms   | 580 ms: 1.43x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['Shelf']                   | 954 ms   | 689 ms: 1.39x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['Shelf']                         | 1.04 sec | 784 ms: 1.33x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['tuple']                   | 558 ms   | 417 ms: 1.34x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['tuple']                         | 649 ms   | 502 ms: 1.29x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['dict']                    | 579 ms   | 464 ms: 1.25x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['dict']                          | 648 ms   | 547 ms: 1.19x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-empty_cls_with_bases-bases=['list']                    | 630 ms   | 476 ms: 1.32x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| 100000-cls_with_bases-bases=['list']                          | 686 ms   | 563 ms: 1.22x faster  |
+---------------------------------------------------------------+----------+-----------------------+
| Geometric mean                                                | (ref)    | 1.34x faster          |
+---------------------------------------------------------------+----------+-----------------------+

Also benchgcclasses2.py output:
ref:

➜ .\python.bat ..\cpython-issues\gh-132042-optimize-class-creation\benchgcclasses2.py
Running Release|x64 interpreter...
GC time: 93.8 ms
gc: collecting generation 2...
gc: objects in each generation: 0 0 905261
gc: objects in permanent generation: 0

➜ .\python.bat ..\cpython-issues\gh-132042-optimize-class-creation\benchgcclasses2.py
Running Release|x64 interpreter...
GC time: 125.0 ms
gc: collecting generation 2...
gc: objects in each generation: 0 0 905261
gc: objects in permanent generation: 0
RSS:

new:

➜ .\python.bat ..\cpython-issues\gh-132042-optimize-class-creation\benchgcclasses2.py
Running Release|x64 interpreter...
GC time: 109.4 ms
gc: collecting generation 2...
gc: objects in each generation: 0 0 905262
gc: objects in permanent generation: 0
RSS:

➜ .\python.bat ..\cpython-issues\gh-132042-optimize-class-creation\benchgcclasses2.py
Running Release|x64 interpreter...
GC time: 125.0 ms
gc: collecting generation 2...
gc: objects in each generation: 0 0 905262
gc: objects in permanent generation: 0
RSS:

Time varies, I'm not sure it is statistically significant. Count of objects closely the same.

Async import time (➜ .\python.bat -X importtime -c 'import asyncio'):
ref:

import time:      1116 |      86283 | asyncio

new:

import time:      1014 |      82194 | asyncio

@sergey-miryanov
Copy link
Contributor Author

Remove resolve_slotdups (new2):

+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| Benchmark                                                   | ref     | new                   | new2                  |
+=============================================================+=========+=======================+=======================+
| 1000-empty_cls                                              | 4.42 ms | 3.50 ms: 1.26x faster | 3.37 ms: 1.31x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_dunders                                       | 5.25 ms | 4.45 ms: 1.18x faster | 4.38 ms: 1.20x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A', 'B']                  | 5.70 ms | 3.84 ms: 1.48x faster | 3.68 ms: 1.55x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['A', 'B']                        | 6.26 ms | 4.62 ms: 1.35x faster | 4.51 ms: 1.39x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A', 'B', 'D']             | 6.49 ms | 4.16 ms: 1.56x faster | 4.00 ms: 1.62x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['A', 'B', 'D']                   | 6.97 ms | 4.94 ms: 1.41x faster | 4.80 ms: 1.45x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A_dun', 'B_dun']          | 5.52 ms | 3.89 ms: 1.42x faster | 3.74 ms: 1.48x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['A_dun', 'B_dun']                | 6.21 ms | 4.67 ms: 1.33x faster | 4.55 ms: 1.36x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun'] | 6.20 ms | 4.20 ms: 1.47x faster | 4.08 ms: 1.52x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['A_dun', 'B_dun', 'D_dun']       | 7.10 ms | 5.02 ms: 1.42x faster | 4.89 ms: 1.45x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['Logger']                  | 5.42 ms | 4.22 ms: 1.28x faster | 4.06 ms: 1.33x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['Logger']                        | 6.05 ms | 5.08 ms: 1.19x faster | 4.97 ms: 1.22x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['DatagramHandler']         | 6.63 ms | 4.42 ms: 1.50x faster | 4.26 ms: 1.56x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['DatagramHandler']               | 7.23 ms | 5.24 ms: 1.38x faster | 5.09 ms: 1.42x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['MagicMock']               | 7.66 ms | 4.95 ms: 1.55x faster | 4.83 ms: 1.59x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['MagicMock']                     | 8.26 ms | 5.74 ms: 1.44x faster | 5.64 ms: 1.46x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['Shelf']                   | 9.46 ms | 6.86 ms: 1.38x faster | 6.67 ms: 1.42x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['Shelf']                         | 10.2 ms | 7.84 ms: 1.30x faster | 7.62 ms: 1.34x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['tuple']                   | 5.62 ms | 4.18 ms: 1.35x faster | 3.82 ms: 1.47x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['tuple']                         | 6.33 ms | 5.53 ms: 1.14x faster | 4.57 ms: 1.39x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['dict']                    | 5.60 ms | 4.90 ms: 1.14x faster | 4.32 ms: 1.30x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['dict']                          | 6.30 ms | 5.56 ms: 1.13x faster | 5.15 ms: 1.22x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-empty_cls_with_bases-bases=['list']                    | 5.99 ms | 4.74 ms: 1.26x faster | 4.39 ms: 1.36x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| 1000-cls_with_bases-bases=['list']                          | 6.68 ms | 5.64 ms: 1.19x faster | 5.18 ms: 1.29x faster |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+
| Geometric mean                                              | (ref)   | 1.34x faster          | 1.40x faster          |
+-------------------------------------------------------------+---------+-----------------------+-----------------------+

@sergey-miryanov sergey-miryanov marked this pull request as ready for review April 9, 2025 20:54
@sergey-miryanov
Copy link
Contributor Author

It is ready to review. Please take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting review interpreter-core (Objects, Python, Grammar, and Parser dirs)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants