Skip to content

Update declarative function#613

Open
frmdstryr wants to merge 2 commits intonucleic:mainfrom
frmdstryr:update-dfunc
Open

Update declarative function#613
frmdstryr wants to merge 2 commits intonucleic:mainfrom
frmdstryr:update-dfunc

Conversation

@frmdstryr
Copy link
Copy Markdown
Contributor

Addresses recent issues and updates to use vectorcalls.

A simple timeit calling a dfunc shows about a 30% speedup with this change (but still over order of magnitude slower than a normal py fn call).

I think it is safe to assume the caller "owns" a reference to several of the arguments so this removes a few increfs (pfunc, pself, and argsptr).

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 7, 2026

Codecov Report

❌ Patch coverage is 0% with 65 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.91%. Comparing base (effc8b3) to head (5338ee4).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #613      +/-   ##
==========================================
- Coverage   65.99%   65.91%   -0.09%     
==========================================
  Files         270      270              
  Lines       26590    26623      +33     
  Branches     3908     3921      +13     
==========================================
  Hits        17549    17549              
- Misses       7992     8025      +33     
  Partials     1049     1049              
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@frmdstryr
Copy link
Copy Markdown
Contributor Author

It looks like call_func has to generate a new function with every call. I wonder if the bound dfunc could somehow cache it

@MatthieuDartiailh
Copy link
Copy Markdown
Member

It looks like call_func has to generate a new function with every call. I wonder if the bound dfunc could somehow cache it

Could you point me to this I do not remember why it is so ?

Copy link
Copy Markdown
Member

@MatthieuDartiailh MatthieuDartiailh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question

Comment on lines -483 to -494
PyObject* pymethod;
if( numfree > 0 )
{
pymethod = pyobject_cast( freelist[ --numfree ] );
_Py_NewReference( pymethod );
}
else
{
pymethod = PyType_GenericAlloc( BoundDMethod::TypeObject, 0 );
if( !pymethod )
return 0;
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove the freelist ?

Copy link
Copy Markdown
Contributor Author

@frmdstryr frmdstryr Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the first issue said there was issues with GC and suggested doing that and I didn't want to look into it.

But since you asked... I re-added it after digging through methodobject.c and the freelist code that I think simply adding the PyObject_GC_Track fixes the GC issue. The BoundDMethod::TypeObject will still leak references (one per freelist obj) but cant be subclassed so I think that's fine.

@frmdstryr
Copy link
Copy Markdown
Contributor Author

frmdstryr commented Apr 22, 2026

It looks like call_func has to generate a new function with every call. I wonder if the bound dfunc could somehow cache it

Could you point me to this I do not remember why it is so ?

Looking at the source of PyEval_EvalCodeEx it creates a new function using _PyFunction_FromConstructor mostly just copying the arguments.

I'm not sure if it can avoid this and somehow just use _PyEval_Vector which takes the locals. I'll open a PR if I can get something working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants