Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34.1k
[WIP] gh-129813, PEP 782: Add PyBytesWriter C API#131681
[WIP] gh-129813, PEP 782: Add PyBytesWriter C API#131681vstinner wants to merge 30 commits intopython:mainfrom
Conversation
Add functions:* PyBytesWriter_Create()* PyBytesWriter_Discard()* PyBytesWriter_Finish()* PyBytesWriter_FinishWithSize()* PyBytesWriter_FinishWithEndPointer()* PyBytesWriter_Data()* PyBytesWriter_Allocated()* PyBytesWriter_SetSize()* PyBytesWriter_Resize()
Convert _PyBytes_FromHex().
Replace PyBytes_FromStringAndSize(NULL, 0) withPy_GetConstant(Py_CONSTANT_EMPTY_BYTES).
vstinner commentedApr 22, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
This change has no impact on performance, even if the new public API allocates memory on the heap, instead of allocating on the stack. It uses a freelist to optimize Microbenchmark on 3 functions, to compare the private
importpyperfimportbinasciirunner=pyperf.Runner()runner.bench_func('from list 100',bytes,list(b'x'*100))runner.bench_func('from list 1,000',bytes,list(b'x'*1_000))runner.bench_func('from hex 100',bytes.fromhex,bytes(range(100)).hex())runner.bench_func('from hex 1,000',bytes.fromhex, (b'x'*1_000).hex())runner.bench_func('b2a_uu',binascii.b2a_uu,b'x'*45) Result:
Benchmark hidden because not significant (1): from list 1,000 |
vstinner commentedApr 22, 2025
Benchmark comparing Benchmark: importpyperfSIZES= (10,100,500)runner=pyperf.Runner()forsizeinSIZES:large_int= (2** (size*8)-1)runner.bench_func(f'to_bytes({size})',large_int.to_bytes,size)forsizeinSIZES:mem=memoryview(b'x'*size)runner.bench_func(f'memoryview({size}).tobytes()',mem.tobytes) Result:
It's hard to beat There is an overhead around10 ns when using |
serhiy-storchaka commentedMay 6, 2025
Could you please benchmark the following?
|
vstinner commentedMay 6, 2025
I wrote a big PR to show how PEP 782 would look like and how it's being used. But if PEP 782 is accepted, I will only start by adding the API without using it. Then I will write separated changes to use the new API and run benchmarks on each change.
I didn't modify these encoders, they still use the private
Same. If I modify these encoders and error handlers later, I will run benchmarks to decide if it's acceptable to use the public API or not. |
vstinner commentedMay 6, 2025
Microbenchmark on Detailsimportpyperfrunner=pyperf.Runner()importctypesfromctypesimportpythonapi,py_objectfromctypesimport (c_int,c_uint,c_long,c_ulong,c_size_t,c_ssize_t,c_char_p)PyBytes_FromFormat=pythonapi.PyBytes_FromFormatPyBytes_FromFormat.argtypes= (c_char_p,)PyBytes_FromFormat.restype=py_objectPyBytes_DecodeEscape=pythonapi.PyBytes_DecodeEscapePyBytes_DecodeEscape.argtypes= (c_char_p,c_size_t,c_char_p,c_size_t,c_char_p)PyBytes_DecodeEscape.restype=py_objectrunner.bench_func('Format hello world',PyBytes_FromFormat,b'Hello %s !',b'world')fmt= (b'Hell%c'+b' '*1024+b' %s')runner.bench_func('Format long format',PyBytes_FromFormat,fmt,c_int(ord('o')),b'world')s=b'abc\\ndef\\x40.'runner.bench_func('Decode simple',PyBytes_DecodeEscape,s,len(s),None,0,b'unused')s=b'x'*1024runner.bench_func('Decode long copy',PyBytes_DecodeEscape,s,len(s),None,0,b'unused')s=b'\\x40'*1024runner.bench_func('Decode long\\x40',PyBytes_DecodeEscape,s,len(s),None,0,b'unused') Results:
Benchmark hidden because not significant (1): Format hello world I'm not sure why PEP 782 is faster, but at least it's not slower :-) I build Python with |
vstinner commentedSep 12, 2025
I started to split this huge PR into smaller PRs, see PRs attached to the issue#129813. |
Uh oh!
There was an error while loading.Please reload this page.
Add functions: