René's URL Explorer Experiment


Title: Speed regression in the decimal module due to using heap types · Issue #144650 · python/cpython · GitHub

Open Graph Title: Speed regression in the decimal module due to using heap types · Issue #144650 · python/cpython

X Title: Speed regression in the decimal module due to using heap types · Issue #144650 · python/cpython

Description: This is essentially a rebirth of #114682, which was closed due to @skrah ban (unfortunately, such things usually don't fix issues). The problem seems to be valid and I open a new issue per kindly @gpshead permission. I labeled issue as "...

Open Graph Description: This is essentially a rebirth of #114682, which was closed due to @skrah ban (unfortunately, such things usually don't fix issues). The problem seems to be valid and I open a new issue per kindly @...

X Description: This is essentially a rebirth of #114682, which was closed due to @skrah ban (unfortunately, such things usually don't fix issues). The problem seems to be valid and I open a new issue per kind...

Opengraph URL: https://github.com/python/cpython/issues/144650

X: @github

direct link

Domain: github.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Speed regression in the decimal module due to using heap types","articleBody":"This is essentially a rebirth of #114682, which was closed due to @skrah ban (unfortunately, such things usually don't fix issues).\n\nThe problem seems to be valid and I open a new issue per kindly @gpshead permission.  I labeled issue as \"type-feature\", but IMO it's looks rather as a regression, i.e. \"type-bug\".\n\nHere benchmarks results (with PGO) for 3.9-3.15:\n| Benchmark         | 39       | 310                    | 311                    | 312                    | 313                    | 314                    | 315                    |\n|-------------------|:--------:|:----------------------:|:----------------------:|:----------------------:|:----------------------:|:----------------------:|:----------------------:|\n| decimal_factorial | 804 ms   | 843 ms: 1.05x slower   | 763 ms: 1.05x faster   | 794 ms: 1.01x faster   | 1.02 sec: 1.27x slower | 950 ms: 1.18x slower   | 951 ms: 1.18x slower   |\n| decimal_pi        | 1.12 sec | 1.26 sec: 1.13x slower | 1.29 sec: 1.15x slower | 1.31 sec: 1.17x slower | 1.86 sec: 1.67x slower | 1.66 sec: 1.48x slower | 1.66 sec: 1.49x slower |\n| Geometric mean    | (ref)    | 1.09x slower           | 1.05x slower           | 1.07x slower           | 1.45x slower           | 1.32x slower           | 1.33x slower           |\n\nBenchmarks were available in the pyperformance package long time ago but are disabled, see https://github.com/python/pyperformance/pull/453 (I use *first* commit from above PR to enable *both* benchmarks.  Though, the \"decimal_factorial\" benchmark seems to be less affected, I guess because it has more large numbers).\n\nN.B.: the \"decimal_pi\" benchmark do computation with low precision (9 and 19).  Here is what happens with the default precision (28):\n| Benchmark  | 39       | 313                    |\n|------------|:--------:|:----------------------:|\n| decimal_pi | 1.20 sec | 1.99 sec: 1.65x slower |\n\nNot much better.\n\nIt seems that major slowdown come in the 3.13 (around 1.67x slower for \"decimal_pi\" on my system) with https://github.com/python/cpython/pull/106079.  Unfortunately, nobody asked to do performance measurements during PR review :(\n\nSomething like this happens already on toy extension types:\n| Benchmark           | ref    | heap                 |\n|---------------------|:------:|:--------------------:|\n| xyz(123) + xyz(321) | 204 ns | 357 ns: 1.75x slower |\n\n\u003cdetails\u003e\n\u003csummary\u003ecode and benchmark\u003c/summary\u003e\n\n```py\n# bench.py\nimport pyperf\nfrom operator import add\nfrom example import xyz\n\nx, y = map(xyz, [123, 321])\nrunner = pyperf.Runner()\ns = repr(x) + \" + \" + repr(y)\nrunner.bench_func(s, add, x, y)\n```\n\n```c\n/* static type */\n\n#define PY_SSIZE_T_CLEAN\n#include \u003cPython.h\u003e\n\ntypedef struct {\n    PyObject_HEAD\n    long value;\n} XYZ_Object;\n\nPyTypeObject XYZ_Type;\n#define XYZ_CheckExact(u) Py_IS_TYPE((u), \u0026XYZ_Type)\n\nstatic XYZ_Object *\nXYZ_new(long value)\n{\n    XYZ_Object *res = PyObject_New(XYZ_Object, \u0026XYZ_Type);\n\n    if (res) {\n        res-\u003evalue = value;\n    }\n    return res;\n}\n\nstatic PyObject *\nnew(PyTypeObject *type, PyObject *args, PyObject *keywds)\n{\n    Py_ssize_t argc = PyTuple_GET_SIZE(args);\n\n    if (argc == 1) {\n        PyObject *arg = PyTuple_GET_ITEM(args, 0);\n        long value = PyLong_AsLong(arg);\n\n        if (value == -1 \u0026\u0026 PyErr_Occurred()) {\n            return NULL;\n        }\n        return (PyObject *)XYZ_new(value);\n    }\n    PyErr_SetString(PyExc_TypeError, \"value required\");\n    return NULL;\n}\n\nstatic PyObject *\nadd(PyObject *self, PyObject *other)\n{\n    XYZ_Object *x = (XYZ_Object *)self;\n    XYZ_Object *y = (XYZ_Object *)other;\n\n    if (XYZ_CheckExact(x) \u0026\u0026 XYZ_CheckExact(y)) {\n        return (PyObject *)XYZ_new(x-\u003evalue + y-\u003evalue);\n    }\n    Py_RETURN_NOTIMPLEMENTED;\n}\n\nstatic PyObject *\nrepr(PyObject *self)\n{\n    return PyUnicode_FromFormat(\"xyz(%ld)\", ((XYZ_Object *)self)-\u003evalue);\n}\n\nstatic PyNumberMethods xyz_as_number = {\n    .nb_add = add,\n};\n\nPyTypeObject XYZ_Type = {\n    PyVarObject_HEAD_INIT(NULL, 0)\n    .tp_name = \"xyz\",\n    .tp_basicsize = sizeof(XYZ_Object),\n    .tp_new = new,\n    .tp_repr = repr,\n    .tp_as_number = \u0026xyz_as_number,\n    .tp_flags = Py_TPFLAGS_DEFAULT,\n};\n\nstatic int\nexample_exec(PyObject *module)\n{\n    if (PyModule_AddType(module, \u0026XYZ_Type) \u003c 0) {\n        return -1;\n    }\n    return 0;\n}\n\n#ifdef __GNUC__\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wpedantic\"\n#endif\nstatic PyModuleDef_Slot example_slots[] = {\n    {Py_mod_exec, example_exec},\n    {0, NULL}};\n#ifdef __GNUC__\n#  pragma GCC diagnostic pop\n#endif\n\nstatic struct PyModuleDef example_module = {\n    PyModuleDef_HEAD_INIT,\n    .m_name = \"example\",\n    .m_doc = \"Test module.\",\n    .m_size = 0,\n    .m_slots = example_slots,\n};\n\nPyMODINIT_FUNC\nPyInit_example(void)\n{\n    return PyModuleDef_Init(\u0026example_module);\n}\n```\n\n```c\n/* heap type */\n\n#define PY_SSIZE_T_CLEAN\n#include \u003cPython.h\u003e\n\ntypedef struct {\n    PyObject_HEAD\n    long value;\n} XYZ_Object;\n\ntypedef struct {\n    PyTypeObject *XYZ_Type;\n} example_state;\n\n#define XYZ_CheckExact(st, u) Py_IS_TYPE((u), (st)-\u003eXYZ_Type)\n\nstatic XYZ_Object *\nXYZ_new(example_state *Py_UNUSED(state), PyTypeObject *type, long value)\n{\n    XYZ_Object *res = PyObject_GC_New(XYZ_Object, type);\n\n    if (res) {\n        PyObject_GC_Track((PyObject *)res);\n        res-\u003evalue = value;\n    }\n    return res;\n}\n\nstatic struct PyModuleDef example_module;\n\nstatic example_state *\nget_state(PyTypeObject *type)\n{\n    PyObject *module = PyType_GetModuleByDef(type, \u0026example_module);\n\n    return PyModule_GetState(module);\n}\n\nstatic PyObject *\nnew(PyTypeObject *type, PyObject *args, PyObject *keywds)\n{\n    Py_ssize_t argc = PyTuple_GET_SIZE(args);\n    example_state *state = get_state(type);\n\n    if (argc == 1) {\n        PyObject *arg = PyTuple_GET_ITEM(args, 0);\n        long value = PyLong_AsLong(arg);\n\n        if (value == -1 \u0026\u0026 PyErr_Occurred()) {\n            return NULL;\n        }\n        return (PyObject *)XYZ_new(state, type, value);\n    }\n    PyErr_SetString(PyExc_TypeError, \"value required\");\n    return NULL;\n}\n\nstatic int\ntraverse(PyObject *self, visitproc visit, void *arg)\n{\n    Py_VISIT(Py_TYPE(self));\n    return 0;\n}\n\nstatic void\ndealloc(PyObject *self)\n{\n    PyTypeObject *type = Py_TYPE(self);\n\n    PyObject_GC_UnTrack(self);\n    type-\u003etp_free(self);\n    Py_DECREF(type);\n}\n\nstatic inline example_state *\nfind_state_left_or_right(PyObject *left, PyObject *right)\n{\n    PyObject *module = PyType_GetModuleByDef(Py_TYPE(left), \u0026example_module);\n\n    if (module) {\n        return PyModule_GetState(module);\n    }\n    PyErr_Clear();\n    return PyType_GetModuleState(Py_TYPE(right));\n}\n\nstatic PyObject *\nadd(PyObject *self, PyObject *other)\n{\n    example_state *state = find_state_left_or_right(self, other);\n    XYZ_Object *x = (XYZ_Object *)self;\n    XYZ_Object *y = (XYZ_Object *)other;\n\n    if (XYZ_CheckExact(state, x) \u0026\u0026 XYZ_CheckExact(state, y)) {\n        return (PyObject *)XYZ_new(state, state-\u003eXYZ_Type, x-\u003evalue + y-\u003evalue);\n    }\n    Py_RETURN_NOTIMPLEMENTED;\n}\n\nstatic PyObject *\nrepr(PyObject *self)\n{\n    return PyUnicode_FromFormat(\"xyz(%ld)\", ((XYZ_Object *)self)-\u003evalue);\n}\n\n#ifdef __GNUC__\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wpedantic\"\n#endif\nstatic PyType_Slot xyz_slots[] = {\n    {Py_tp_repr, repr},\n    {Py_tp_new, new},\n    {Py_nb_add, add},\n    {Py_tp_traverse, traverse},\n    {Py_tp_dealloc, dealloc},\n};\n#ifdef __GNUC__\n#  pragma GCC diagnostic pop\n#endif\n\nstatic PyType_Spec xyz_spec = {\n    .name = \"xyz\",\n    .basicsize = sizeof(XYZ_Object),\n    .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE,\n    .slots = xyz_slots,\n};\n\nstatic int\nexample_exec(PyObject *module)\n{\n    example_state *state = PyModule_GetState(module);\n\n    state-\u003eXYZ_Type = (PyTypeObject *)PyType_FromModuleAndSpec(module,\n                                                               \u0026xyz_spec,\n                                                               NULL);\n    if (!state-\u003eXYZ_Type || PyModule_AddType(module, state-\u003eXYZ_Type) \u003c 0) {\n        return -1;\n    }\n    return 0;\n}\n\nstatic int\nexample_clear(PyObject *module)\n{\n    example_state *state = PyModule_GetState(module);\n\n    Py_CLEAR(state-\u003eXYZ_Type);\n    return 0;\n}\n\nstatic int\nexample_traverse(PyObject *module, visitproc visit, void *arg)\n{\n    example_state *state = PyModule_GetState(module);\n\n    Py_VISIT(state-\u003eXYZ_Type);\n    return 0;\n}\n\n#ifdef __GNUC__\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wpedantic\"\n#endif\nstatic PyModuleDef_Slot example_slots[] = {\n    {Py_mod_exec, example_exec},\n    {0, NULL}};\n#ifdef __GNUC__\n#  pragma GCC diagnostic pop\n#endif\n\nstatic struct PyModuleDef example_module = {\n    PyModuleDef_HEAD_INIT,\n    .m_name = \"example\",\n    .m_doc = \"Test module.\",\n    .m_size = 0,\n    .m_slots = example_slots,\n    .m_clear = example_clear,\n    .m_traverse = example_traverse,\n};\n\nPyMODINIT_FUNC\nPyInit_example(void)\n{\n    return PyModuleDef_Init(\u0026example_module);\n}\n```\n\n\u003c/details\u003e\n\nSo, what we could do?  Can heap types (at least immutable) be less costly c.f. static types?  Can we convert the decimal module back to static types?\n\nI tried to add a freelist for Decimal's (quick patch is there: https://github.com/skirpichev/cpython/pull/16).  It looks this will mitigate the problem, but not entirely fix regression.\n","author":{"url":"https://github.com/skirpichev","@type":"Person","name":"skirpichev"},"datePublished":"2026-02-10T07:29:14.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":7},"url":"https://github.com/144650/cpython/issues/144650"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:da17ac96-07ab-a6b3-51e8-48d0f651535b
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-id9012:CD430:C2697A:11C7F3C:6A5761DD
html-safe-nonce7d3528eb373ec47199c48d861992c5bc3cdde0157fccd91eed53d3c02c4957fb
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5MDEyOkNENDMwOkMyNjk3QToxMUM3RjNDOjZBNTc2MUREIiwidmlzaXRvcl9pZCI6IjE4NzIzMzQ3NTE4Nzg1NzA0NjEiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmacad494cff9ec7dd25c9200f892de741f623fb897724a086a0685e2e6e214299aa
hovercard-subject-tagissue:3919889859
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/144650/issue_layout
twitter:imagehttps://opengraph.githubassets.com/c1928ed67ae62e5390e36e2c3c929fb666edd4108cb18ea826354b6f3e9dab49/python/cpython/issues/144650
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/c1928ed67ae62e5390e36e2c3c929fb666edd4108cb18ea826354b6f3e9dab49/python/cpython/issues/144650
og:image:altThis is essentially a rebirth of #114682, which was closed due to @skrah ban (unfortunately, such things usually don't fix issues). The problem seems to be valid and I open a new issue per kindly @...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernameskirpichev
hostnamegithub.com
expected-hostnamegithub.com
None4e7a7296a3830877cf21a6ad2a972c9e618a48915e03966cf0c53eb08e5aad98
turbo-cache-controlno-preview
go-importgithub.com/python/cpython git https://github.com/python/cpython.git
octolytics-dimension-user_id1525981
octolytics-dimension-user_loginpython
octolytics-dimension-repository_id81598961
octolytics-dimension-repository_nwopython/cpython
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id81598961
octolytics-dimension-repository_network_root_nwopython/cpython
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release87685a1c739dbf97e95760413799bb0221799457
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://github.com/python/cpython/issues/144650#start-of-content
https://github.com/
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fissues%2F144650
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub Copilot appDirect agents from issue to mergehttps://github.com/features/ai/github-app
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
View all resourceshttps://github.com/resources
GitHub SponsorsFund open source developershttps://github.com/open-source/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/open-source/accelerator
GitHub Starshttps://stars.github.com
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/enterprise/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fpython%2Fcpython%2Fissues%2F144650
Sign up https://github.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=python%2Fcpython
Reloadhttps://github.com/python/cpython/issues/144650
Reloadhttps://github.com/python/cpython/issues/144650
Reloadhttps://github.com/python/cpython/issues/144650
Please reload this pagehttps://github.com/python/cpython/issues/144650
python https://github.com/python
cpythonhttps://github.com/python/cpython
Please reload this pagehttps://github.com/python/cpython/issues/144650
Notifications https://github.com/login?return_to=%2Fpython%2Fcpython
Fork 35k https://github.com/login?return_to=%2Fpython%2Fcpython
Star 73.8k https://github.com/login?return_to=%2Fpython%2Fcpython
Code https://github.com/python/cpython
Issues 5k+ https://github.com/python/cpython/issues
Pull requests 2.3k https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality 0 https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
Code https://github.com/python/cpython
Issues https://github.com/python/cpython/issues
Pull requests https://github.com/python/cpython/pulls
Actions https://github.com/python/cpython/actions
Projects https://github.com/python/cpython/projects
Security and quality https://github.com/python/cpython/security
Insights https://github.com/python/cpython/pulse
Speed regression in the decimal module due to using heap typeshttps://github.com/python/cpython/issues/144650#top
extension-modulesC modules in the Modules dirhttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22extension-modules%22
performancePerformance or resource usagehttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22performance%22
topic-subinterpretershttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22topic-subinterpreters%22
type-featureA feature request or enhancementhttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22type-feature%22
https://github.com/skirpichev
skirpichevhttps://github.com/skirpichev
on Feb 10, 2026https://github.com/python/cpython/issues/144650#issue-3919889859
#114682https://github.com/python/cpython/issues/114682
@skrahhttps://github.com/skrah
@gpsheadhttps://github.com/gpshead
python/pyperformance#453https://github.com/python/pyperformance/pull/453
#106079https://github.com/python/cpython/pull/106079
skirpichev#16https://github.com/skirpichev/cpython/pull/16
extension-modulesC modules in the Modules dirhttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22extension-modules%22
performancePerformance or resource usagehttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22performance%22
topic-subinterpretershttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22topic-subinterpreters%22
type-featureA feature request or enhancementhttps://github.com/python/cpython/issues?q=state%3Aopen%20label%3A%22type-feature%22
Subinterpretershttps://github.com/orgs/python/projects/3
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.