You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Change PyMem_Malloc to use pymalloc allocator #70437
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2016-04-26.11:37:12.570>created_at=<Date2016-01-31.17:48:24.357>labels= ['performance']
title='Change PyMem_Malloc to use pymalloc allocator'updated_at=<Date2016-04-26.11:37:12.569>user='https://github.com/vstinner'
The issue bpo-23601 showed speedup for the dict type by replacing PyMem_Malloc() with PyObject_Malloc() in dictobject.c.
When I worked on the PEP-445, it was discussed to use the Python fast memory allocator for small memory allocations (<= 512 bytes), but I think that nobody tested on benchmark.
So I open an issue to discuss that.
By the way, we should also benchmark the Windows memory allocator which limits fragmentations. Maybe we can skip the Python small memory allocator on recent version of Windows?
Attached patch implements the change. The main question is the speedup on various kinds of memory allocations (need a benchmark) :-)
I will try to run benchmarks.
--
If the patch slows down Python, maybe we can investigate if some Python types (like dict) mostly uses "small" memory blocks (<= 512 bytes).
Hum, the point of PyMem_Malloc() is that it's distinct from PyObject_Malloc(), right? Why would you redirect one to the other?
For performances.
(of course, we might question why we have two different families of allocation APIs...)
That's the real question: why does Python have PyMem family? Is it still justified in 2016?
--
Firefox uses jemalloc to limit the fragmentation of the heap memory. Once I spent a lot of time to try to understand the principle of fragmentation, and in my tiny benchmarks, jemalloc was *much* better than system allocator. By the way, jemalloc scales well on multiple threads ;-)
FYI benchmark result to compare Python with and without pymalloc (fast memory allocator for block <= 512 bytes). As expected, no pymalloc is slower, up to 30% slower (and it's never faster).
Report on Linux smithers 4.3.3-300.fc23.x86_64 #1 SMP Tue Jan 5 23:31:01 UTC 2016 x86_64 x86_64
Total CPU cores: 8
Test with jemalloc using the shell script "python.jemalloc":
---
#!/bin/sh
LD_PRELOAD=/usr/lib64/libjemalloc.so /home/haypo/prog/python/default/python "$@"
---
Using the issue bpo-26516 (PYTHONMALLOC=debug), we can check PyGILState_Check() at runtime, but there is currently an issue related to sub-interpreters. The assertion fails in support.run_in_subinterp(), function used by test_threading and test_capi for example.
I created bpo-26558 to implement GIL checks in PyMem_Malloc() and PyObject_Malloc().
I was very surprised to see a regression in test_format since I didn't change any change related to bytes, bytearray or str formatting in this issue.
In fact, it's much better than that! With PyMem_Malloc() using pymalloc, we benefit for free of the cheap "_Py_AllocatedBlocks" memory leak detector. I introduced the memory leak in the issue bpo-25349 when I optimimzed bytes%args and bytearray%args using the new _PyBytesWriter API.
This memory leak gave me an idea, I opened the issue bpo-26850: "PyMem_RawMalloc(): update also sys.getallocatedblocks() in debug mode".
Activity
vstinner commentedon Jan 31, 2016
The issue bpo-23601 showed speedup for the dict type by replacing PyMem_Malloc() with PyObject_Malloc() in dictobject.c.
When I worked on the PEP-445, it was discussed to use the Python fast memory allocator for small memory allocations (<= 512 bytes), but I think that nobody tested on benchmark.
So I open an issue to discuss that.
By the way, we should also benchmark the Windows memory allocator which limits fragmentations. Maybe we can skip the Python small memory allocator on recent version of Windows?
Attached patch implements the change. The main question is the speedup on various kinds of memory allocations (need a benchmark) :-)
I will try to run benchmarks.
--
If the patch slows down Python, maybe we can investigate if some Python types (like dict) mostly uses "small" memory blocks (<= 512 bytes).
vstinner commentedon Jan 31, 2016
Ok, to avoid confusion, I opened an issue specific to Windows for its "Low-fragmentation Heap": issue bpo-26251.
Other issues related to memory allocators.
Merged:
Open:
pitrou commentedon Feb 2, 2016
Hum, the point of PyMem_Malloc() is that it's distinct from PyObject_Malloc(), right? Why would you redirect one to the other?
pitrou commentedon Feb 2, 2016
(of course, we might question why we have two different families of allocation APIs...)
vstinner commentedon Feb 2, 2016
For performances.
That's the real question: why does Python have PyMem family? Is it still justified in 2016?
--
Firefox uses jemalloc to limit the fragmentation of the heap memory. Once I spent a lot of time to try to understand the principle of fragmentation, and in my tiny benchmarks, jemalloc was *much* better than system allocator. By the way, jemalloc scales well on multiple threads ;-)
My notes on heap memory fragmentation: http://haypo-notes.readthedocs.org/heap_fragmentation.html
vstinner commentedon Feb 2, 2016
About heap memory fragmentation, see also my attached two "benchmarks" in Python and C: python_memleak.py and tu_malloc.c.
vstinner commentedon Feb 2, 2016
So, I ran ssh://hg@hg.python.org/benchmarks with my patch. It looks like some benchmarks are up to 4% faster:
INFO:root:Automatically selected timer: perf_counter
[ 1/10] 2to3...
INFO:root:Running
../default/python.pymem lib3/2to3/2to3 -f all lib/2to3INFO:root:Running
../default/python.pymem lib3/2to3/2to3 -f all lib/2to31 timeINFO:root:Running
../default/python.orig lib3/2to3/2to3 -f all lib/2to3INFO:root:Running
../default/python.orig lib3/2to3/2to3 -f all lib/2to31 time[ 2/10] chameleon_v2...
INFO:root:Running
../default/python.pymem performance/bm_chameleon_v2.py -n 50 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_chameleon_v2.py -n 50 --timer perf_counter[ 3/10] django_v3...
INFO:root:Running
../default/python.pymem performance/bm_django_v3.py -n 50 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_django_v3.py -n 50 --timer perf_counter[ 4/10] fastpickle...
INFO:root:Running
../default/python.pymem performance/bm_pickle.py -n 50 --timer perf_counter --use_cpickle pickleINFO:root:Running
../default/python.orig performance/bm_pickle.py -n 50 --timer perf_counter --use_cpickle pickle[ 5/10] fastunpickle...
INFO:root:Running
../default/python.pymem performance/bm_pickle.py -n 50 --timer perf_counter --use_cpickle unpickleINFO:root:Running
../default/python.orig performance/bm_pickle.py -n 50 --timer perf_counter --use_cpickle unpickle[ 6/10] json_dump_v2...
INFO:root:Running
../default/python.pymem performance/bm_json_v2.py -n 50 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_json_v2.py -n 50 --timer perf_counter[ 7/10] json_load...
INFO:root:Running
../default/python.pymem performance/bm_json.py -n 50 --timer perf_counter json_loadINFO:root:Running
../default/python.orig performance/bm_json.py -n 50 --timer perf_counter json_load[ 8/10] nbody...
INFO:root:Running
../default/python.pymem performance/bm_nbody.py -n 50 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_nbody.py -n 50 --timer perf_counter[ 9/10] regex_v8...
INFO:root:Running
../default/python.pymem performance/bm_regex_v8.py -n 50 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_regex_v8.py -n 50 --timer perf_counter[10/10] tornado_http...
INFO:root:Running
../default/python.pymem performance/bm_tornado_http.py -n 100 --timer perf_counterINFO:root:Running
../default/python.orig performance/bm_tornado_http.py -n 100 --timer perf_counterReport on Linux smithers 4.3.3-300.fc23.x86_64 #1 SMP Tue Jan 5 23:31:01 UTC 2016 x86_64 x86_64
Total CPU cores: 8
### 2to3 ###
6.880090 -> 6.818911: 1.01x faster
### fastpickle ###
Min: 0.453826 -> 0.442081: 1.03x faster
Avg: 0.456499 -> 0.443978: 1.03x faster
Significant (t=20.03)
Stddev: 0.00370 -> 0.00242: 1.5293x smaller
### fastunpickle ###
Min: 0.547908 -> 0.526027: 1.04x faster
Avg: 0.554663 -> 0.528686: 1.05x faster
Significant (t=15.95)
Stddev: 0.00893 -> 0.00728: 1.2260x smaller
### json_dump_v2 ###
Min: 2.733907 -> 2.627718: 1.04x faster
Avg: 2.762473 -> 2.664675: 1.04x faster
Significant (t=11.99)
Stddev: 0.03796 -> 0.04341: 1.1435x larger
### regex_v8 ###
Min: 0.042438 -> 0.042581: 1.00x slower
Avg: 0.042805 -> 0.044078: 1.03x slower
Significant (t=-2.12)
Stddev: 0.00171 -> 0.00388: 2.2694x larger
### tornado_http ###
Min: 0.254089 -> 0.246088: 1.03x faster
Avg: 0.257046 -> 0.249033: 1.03x faster
Significant (t=15.83)
Stddev: 0.00401 -> 0.00310: 1.2930x smaller
The following not significant results are hidden, use -v to show them:
chameleon_v2, django_v3, json_load, nbody.
real 19m13.413s
user 18m50.024s
sys 0m22.507s
YurySelivanov commentedon Feb 2, 2016
Please use -r flag for perf.py
pitrou commentedon Feb 2, 2016
What this says is that some internals uses of PyMem_XXX should be replaced with PyObject_XXX.
vstinner commentedon Feb 2, 2016
FYI benchmark result to compare Python with and without pymalloc (fast memory allocator for block <= 512 bytes). As expected, no pymalloc is slower, up to 30% slower (and it's never faster).
Report on Linux smithers 4.3.3-300.fc23.x86_64 #1 SMP Tue Jan 5 23:31:01 UTC 2016 x86_64 x86_64
Total CPU cores: 8
### 2to3 ###
7.253671 -> 7.558993: 1.04x slower
### chameleon_v2 ###
Min: 5.598481 -> 5.794526: 1.04x slower
Avg: 5.714233 -> 5.922142: 1.04x slower
Significant (t=-8.01)
Stddev: 0.15956 -> 0.09048: 1.7636x smaller
### django_v3 ###
Min: 0.574221 -> 0.606462: 1.06x slower
Avg: 0.579659 -> 0.612088: 1.06x slower
Significant (t=-28.44)
Stddev: 0.00605 -> 0.00532: 1.1371x smaller
### fastpickle ###
Min: 0.450852 -> 0.502645: 1.11x slower
Avg: 0.455619 -> 0.513777: 1.13x slower
Significant (t=-26.24)
Stddev: 0.00696 -> 0.01404: 2.0189x larger
### fastunpickle ###
Min: 0.544064 -> 0.696306: 1.28x slower
Avg: 0.552459 -> 0.705372: 1.28x slower
Significant (t=-85.52)
Stddev: 0.00798 -> 0.00980: 1.2281x larger
### json_dump_v2 ###
Min: 2.780312 -> 3.265531: 1.17x slower
Avg: 2.830463 -> 3.370060: 1.19x slower
Significant (t=-23.73)
Stddev: 0.04190 -> 0.15521: 3.7046x larger
### json_load ###
Min: 0.428893 -> 0.558956: 1.30x slower
Avg: 0.431941 -> 0.569441: 1.32x slower
Significant (t=-74.76)
Stddev: 0.00791 -> 0.01033: 1.3060x larger
### regex_v8 ###
Min: 0.043439 -> 0.044614: 1.03x slower
Avg: 0.044388 -> 0.046487: 1.05x slower
Significant (t=-4.95)
Stddev: 0.00215 -> 0.00209: 1.0283x smaller
### tornado_http ###
Min: 0.264603 -> 0.278840: 1.05x slower
Avg: 0.270153 -> 0.285263: 1.06x slower
Significant (t=-23.04)
Stddev: 0.00489 -> 0.00436: 1.1216x smaller
The following not significant results are hidden, use -v to show them:
nbody.
vstinner commentedon Feb 2, 2016
Test with jemalloc using the shell script "python.jemalloc":
---
#!/bin/sh
LD_PRELOAD=/usr/lib64/libjemalloc.so /home/haypo/prog/python/default/python "$@"
---
Memory consumption:
python3 -u perf.py -m ../default/python ../default/python.jemalloc
Report on Linux smithers 4.3.3-300.fc23.x86_64 #1 SMP Tue Jan 5 23:31:01 UTC 2016 x86_64 x86_64
Total CPU cores: 8
### 2to3 ###
Mem max: 43100.000 -> 220.000: 195.9091x smaller
### chameleon_v2 ###
Mem max: 367276.000 -> 224.000: 1639.6250x smaller
### django_v3 ###
Mem max: 24136.000 -> 284.000: 84.9859x smaller
### fastpickle ###
Mem max: 8692.000 -> 284.000: 30.6056x smaller
### fastunpickle ###
Mem max: 8704.000 -> 216.000: 40.2963x smaller
### json_dump_v2 ###
Mem max: 10448.000 -> 216.000: 48.3704x smaller
### json_load ###
Mem max: 8444.000 -> 220.000: 38.3818x smaller
### nbody ###
Mem max: 7388.000 -> 220.000: 33.5818x smaller
### regex_v8 ###
Mem max: 12764.000 -> 220.000: 58.0182x smaller
### tornado_http ###
Mem max: 28216.000 -> 228.000: 123.7544x smaller
Performance:
Report on Linux smithers 4.3.3-300.fc23.x86_64 #1 SMP Tue Jan 5 23:31:01 UTC 2016 x86_64 x86_64
Total CPU cores: 8
### 2to3 ###
7.413484 -> 7.189792: 1.03x faster
### chameleon_v2 ###
Min: 5.559697 -> 5.869468: 1.06x slower
Avg: 5.672448 -> 6.033152: 1.06x slower
Significant (t=-13.67)
Stddev: 0.12098 -> 0.14203: 1.1740x larger
### nbody ###
Min: 0.242194 -> 0.229747: 1.05x faster
Avg: 0.244991 -> 0.235297: 1.04x faster
Significant (t=9.75)
Stddev: 0.00262 -> 0.00652: 2.4861x larger
### regex_v8 ###
Min: 0.042532 -> 0.046920: 1.10x slower
Avg: 0.043249 -> 0.047907: 1.11x slower
Significant (t=-13.23)
Stddev: 0.00180 -> 0.00172: 1.0503x smaller
### tornado_http ###
Min: 0.265755 -> 0.274526: 1.03x slower
Avg: 0.273617 -> 0.284186: 1.04x slower
Significant (t=-6.67)
Stddev: 0.00583 -> 0.01474: 2.5297x larger
The following not significant results are hidden, use -v to show them:
django_v3, fastpickle, fastunpickle, json_dump_v2, json_load.
vstinner commentedon Feb 2, 2016
Why not changing PyMem_XXX to use the same fast allocator than PyObject_XXX? (as proposed in this issue)
FYI we now also have the PyMem_RawXXX family :)
pitrou commentedon Feb 2, 2016
Le 02/02/2016 15:47, STINNER Victor a écrit :
These figures are not even remotely believable.
It would make sense to investigate them before posting such numbers ;-)
pitrou commentedon Feb 2, 2016
Le 02/02/2016 15:48, STINNER Victor a écrit :
Why have two sets of functions doing exactly the same thing?
27 remaining items
vstinner commentedon Mar 14, 2016
pymalloc.patch: Updated patch.
vstinner commentedon Mar 14, 2016
I created bpo-26558 to implement GIL checks in PyMem_Malloc() and PyObject_Malloc().
vstinner commentedon Mar 14, 2016
I created the issue bpo-26563 "PyMem_Malloc(): check that the GIL is hold in debug hooks".
python-dev commentedon Apr 22, 2016
New changeset 68b2a43d8653 by Victor Stinner in branch 'default':
PyMem_Malloc() now uses the fast pymalloc allocator
https://hg.python.org/cpython/rev/68b2a43d8653
python-dev commentedon Apr 22, 2016
New changeset 104ed24ebbd0 by Victor Stinner in branch 'default':
Issue bpo-26249: Try test_capi on Windows
https://hg.python.org/cpython/rev/104ed24ebbd0
python-dev commentedon Apr 24, 2016
New changeset 7acad5d8f80e by Victor Stinner in branch 'default':
Issue bpo-26249: Mention PyMem_Malloc() change in What's New in Python 3.6 in the
https://hg.python.org/cpython/rev/7acad5d8f80e
vstinner commentedon Apr 24, 2016
I documented the change, buildbots are happy, I close the issue.
serhiy-storchaka commentedon Apr 25, 2016
68b2a43d8653 introduced memory leak.
python-dev commentedon Apr 26, 2016
New changeset 090502a0c69c by Victor Stinner in branch 'default':
Issue bpo-25349, bpo-26249: Fix memleak in formatfloat()
https://hg.python.org/cpython/rev/090502a0c69c
vstinner commentedon Apr 26, 2016
I was very surprised to see a regression in test_format since I didn't change any change related to bytes, bytearray or str formatting in this issue.
In fact, it's much better than that! With PyMem_Malloc() using pymalloc, we benefit for free of the cheap "_Py_AllocatedBlocks" memory leak detector. I introduced the memory leak in the issue bpo-25349 when I optimimzed bytes%args and bytearray%args using the new _PyBytesWriter API.
This memory leak gave me an idea, I opened the issue bpo-26850: "PyMem_RawMalloc(): update also sys.getallocatedblocks() in debug mode".
vstinner commentedon Apr 26, 2016
There are no more know bugs related to this change, I close the issue. Thanks for the test_format report Serhiy, I missed it.