gh-92810: Reduce memory usage by ABCMeta.__subclasscheck__#131914
gh-92810: Reduce memory usage by ABCMeta.__subclasscheck__#131914dolfinus wants to merge 42 commits intopython:mainfrom
Conversation
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
3 similar comments
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
Signed-off-by: Martynov Maxim <martinov_m_s_@mail.ru>
Signed-off-by: Martynov Maxim <martinov_m_s_@mail.ru>
Signed-off-by: Martynov Maxim <martinov_m_s_@mail.ru>
Signed-off-by: Martynov Maxim <martinov_m_s_@mail.ru>
Signed-off-by: Martynov Maxim <martinov_m_s_@mail.ru>
abf4bfe to
b7603e0
Compare
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool. If this change has little impact on Python users, wait for a maintainer to apply the |
|
pyperformance results doesn't show a much difference: sudo ./venv/bin/python -m pyperf system tune
./venv/bin/python -m pyperformance run --rigorous --affinity 0,1,2,3,4,5main_cd4d0ae75c_rigorous_affinity.json DetailsBenchmarks with tag 'apps':
Benchmark hidden because not significant (1): html5lib Benchmarks with tag 'asyncio':
Benchmark hidden because not significant (13): async_tree_eager_tg, asyncio_tcp, async_tree_cpu_io_mixed, async_tree_none, async_tree_eager_io_tg, async_tree_memoization, async_tree_eager, asyncio_websockets, asyncio_tcp_ssl, async_tree_eager_io, coroutines, async_tree_io, async_tree_eager_memoization_tg Benchmarks with tag 'math':
Benchmark hidden because not significant (1): float Benchmarks with tag 'regex':
Benchmarks with tag 'serialize':
Benchmark hidden because not significant (4): xml_etree_iterparse, unpickle_list, unpickle_pure_python, pickle Benchmarks with tag 'startup':
Benchmarks with tag 'template':
Benchmark hidden because not significant (1): mako All benchmarks:
Benchmark hidden because not significant (38): xml_etree_iterparse, unpickle_list, bench_mp_pool, subparsers, sqlglot_v2_transpile, sqlalchemy_declarative, async_tree_eager_tg, many_optionals, unpickle_pure_python, deltablue, meteor_contest, sqlalchemy_imperative, html5lib, asyncio_tcp, bench_thread_pool, async_tree_cpu_io_mixed, async_tree_none, async_tree_eager_io_tg, telco, generators, sqlglot_v2_parse, async_tree_memoization, scimark_sor, pickle, gc_traversal, async_tree_eager, asyncio_websockets, sqlite_synth, asyncio_tcp_ssl, float, deepcopy, deepcopy_reduce, mako, logging_silent, async_tree_eager_io, coroutines, async_tree_io, async_tree_eager_memoization_tg |
|
I've updated microbenchmark script and results in the PR description: #131914 (comment). Previous microbenchmark implementation created global large class tree, and tested different According to these results, and to pyperformance run on my machine, timing is not that different comparing to |
|
Alternative implementation which eliminates |
|
I've seen your work but I really don't have enough time to estimate the impact for all cases. It's not that it's a bad change but
|
|
Thanks @picnixz, I understand your point. There is no rush here, the change can be landed any time. |
+1 That sounds good. The PR with new tests can be merged as is and then we can continue working on this ensure that the behavior remains same. |
|
Extracted tests into #144941 |
_abc._abc_subclasscheckhas very poor performance and (I think) a memory leak #92810For python build using
--enable-optimizations:benchmark.py
isinstance(child, Parent)2MiB...15MiB
3MiB...15MiB
10MiB...24MiB
10MiB...24MiB
issubclass(Child, Parent)0MiB...1MiB
0MiB...1MiB
6MiB...8MiB
5MiB...8MiB
isinstance(child, Grandparent)0MiB...2MiB
0MiB...1MiB
4MiB...7MiB
4MiB...7MiB
issubclass(Child, Grandparent)0MiB
0MiB
1MiB...2MiB
0MiB...1MiB
not isinstance(child, Sibling)1MiB...14MiB
1MiB...14MiB
14MiB...24MiB
13MiB...22MiB
not issubclass(Child, Sibling)0MiB
0MiB...1MiB
9MiB...11MiB
8MiB...11MiB
not isinstance(child, Cousin)0MiB
1MiB...2MiB
8MiB...10MiB
7MiB...9MiB
not issubclass(Child, Cousin)0MiB
0MiB...1MiB
5MiB...6MiB
3MiB...4MiB
not isinstance(child, Uncle)5706MiB...6331MiB
0MiB...1MiB
3796MiB...4423MiB
6MiB
not issubclass(Child, Uncle)5704MiB
0MiB
3794MiB...3795MiB
4MiB
Memory increment is measured during
isinstance()/issubclass()calls, not during preparation, like class creation or registration where actual registry allocation is performed. So memory usage in tables below is almost always 0.Timing drop for 2 first rows is mostly due to
cls._abc_cache.add(scls)call withindef register(slc, scls)which wasn't implemented before.isinstance(child, Parent.register)0MiB
0MiB
0MiB
0MiB
issubclass(Child, Parent.register)0MiB
0MiB
0MiB
0MiB
isinstance(child, Grandparent.register)0MiB
0MiB
0MiB
0MiB
issubclass(Child, Grandparent.register)0MiB
0MiB
0MiB
0MiB
not isinstance(child, Sibling.register)0MiB
1MiB
0MiB
2MiB
not issubclass(Child, Sibling.register)0MiB
1MiB
0MiB
2MiB
not isinstance(child, Cousin.register)0MiB
2MiB
0MiB
3MiB
not issubclass(Child, Cousin.register)0MiB
2MiB
0MiB
3MiB
not isinstance(child, Uncle.register)0MiB
2MiB...3MiB
0MiB
4MiB
not issubclass(Child, Uncle.register)0MiB
2MiB
0MiB
4MiB
This became a bit slower due to new checks, but this is rare case.
isinstance(child, Parent.__subclasses__)0MiB
0MiB
0MiB
0MiB
issubclass(Child, Parent.__subclasses__)0MiB
0MiB
0MiB
0MiB
isinstance(child, Grandparent.__subclasses__)0MiB
0MiB
0MiB
0MiB
issubclass(Child, Grandparent.__subclasses__)0MiB
0MiB
0MiB
0MiB
not isinstance(child, Sibling.__subclasses__)0MiB
0MiB
0MiB
1MiB
not issubclass(Child, Sibling.__subclasses__)0MiB
0MiB
0MiB
1MiB
not isinstance(child, Cousin.__subclasses__)0MiB
0MiB
0MiB
1MiB
not issubclass(Child, Cousin.__subclasses__)0MiB
0MiB
0MiB
1MiB
not isinstance(child, Uncle.__subclasses__)0MiB
1MiB
0MiB
2MiB
not issubclass(Child, Uncle.__subclasses__)0MiB
0MiB
0MiB
2MiB
Flamegraphs for
_py_abcimpl and testissubclass_uncle(the most time and memory consuming case onmain):main_vs_pr131914.tar.gz