New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance hints for nogil functions requiring exception checks #5673
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. Does this also solve the problem that we issue warnings from within utility code?
Cython/Compiler/Symtab.py
Outdated
pos_filetype = pos[0]._file_type if pos else None | ||
if (type.exception_check and type.exception_value is None and type.nogil and | ||
not pos[0].is_utility_code and | ||
defining and # don't warn about external functions here - the user likely can't do anything | ||
pos_filetype != 'pxd' # again, exclude extern functions (is_pxd is unreliable here) | ||
): | ||
msg = ( | ||
"Exception check on '%s' will always require the GIL to be acquired. Possible solutions:" | ||
"\n\t1. Declare the function as 'noexcept' if you're sure the function should not raise exceptions." | ||
) % name | ||
if type.return_type.is_void: | ||
msg += "\n\t2. Return a dummy integer for Cython to use as an exception flag." | ||
performance_hint(pos, msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that you managed to write more or less the same message twice in two entirely different wordings but with just a few additional conditions in the second incarnation, this loudly screams for a shared helper function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, "requires to be reacquired" sounds funny. Maybe there's a different word that you could use for one or the other.
Cython/Compiler/Symtab.py
Outdated
@@ -931,6 +931,19 @@ def declare_cfunction(self, name, type, pos, | |||
var_entry.scope = entry.scope | |||
entry.as_variable = var_entry | |||
type.entry = entry | |||
pos_filetype = pos[0]._file_type if pos else None | |||
if (type.exception_check and type.exception_value is None and type.nogil and | |||
not pos[0].is_utility_code and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in_utility_code
would read a bit better here, I think. Just a suggestion.
Not in this PR. But it could probably be used as a mechanism to do so. |
Co-authored-by: scoder <stefan_ml@behnel.de>
Cython/Compiler/Errors.py
Outdated
@@ -284,3 +298,14 @@ def reset(): | |||
|
|||
def get_errors_count(): | |||
return threadlocal.cython_errors_count | |||
|
|||
def noexcept_performance_hint_helper(pos, function_name = None, void_return = False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- "xyz_helper" is rarely a good name for a function since every function helps with something. That doesn't tell much about what it actually does. Actual verbs like
write_
orissue_
seem better.
def noexcept_performance_hint_helper(pos, function_name = None, void_return = False): | |
def write_noexcept_performance_hint(pos, function_name=None, void_return=False): |
- This seems too specific for
Errors.py
. You probably considered a couple of places before you put it here, and I agree that it's not easy to decide. But maybe somewhere inPyrexTypes.py
? The hint that we give seems mostly related to C function types. I would consider adding a new module for this, but I'm not sure that we will have many cases where we issue the same hint from more than one place. We'll see about that…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created a new module (and also moved one function in ExprNodes that seemed to fit in the same place).
If you think that's excessive I can put it in PyrexTypes though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed my mind because it caused a circular import and just moved it to PyrexTypes
Cython/Compiler/Symtab.py
Outdated
if (type.exception_check and type.exception_value is None and type.nogil and | ||
not pos[0].in_utility_code and | ||
defining and # don't warn about external functions here - the user likely can't do anything | ||
pos_filetype != 'pxd' # again, exclude extern functions (is_pxd is unreliable here) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Does this also exclude inline functions in .pxd files?
- Why is
is_pxd
unreliable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Does this also exclude inline functions in .pxd files?
Yes - intentionally (I'm working on the basis that anything in a pxd is likely something the user doesn't control, and that they get a message when they use it anyway)
- Why is is_pxd unreliable?
Not sure off the top of my head, but it didn't seem to be set in the example that I tested. I'll go back and see if I can fix that though.
(Will also come back to the other two comments later)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like in_pxd
means that Cython generates code to cimport the function by declaring function pointers (which conflicts with inline
). I've had a go at trying to fix that so it's probably a bit better.
runtests.py
Outdated
def getperformancehints(self): | ||
return self._collect()[2] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used anywhere? Do we need to add it? (And, BTW, are the other two corresponding methods really used anywhere?)
runtests.py
Outdated
expect_errors=False, expect_warnings=False, annotate=False, cleanup_workdir=True, | ||
expect_errors=False, expect_warnings=False, expect_perf_hints=False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's time to clean this up and pass a single expect_log=('warnings', 'errors')
option around (name is up for debate…). We're really carrying around a lot of options by now, and I feel bad every time I add one to the list.
Doesn't have to be in this PR, though. Adding this one doesn't make it much worse.
Co-authored-by: scoder <stefan_ml@behnel.de>
Co-authored-by: scoder <stefan_ml@behnel.de>
I've created a "not warning" category of message to alert users to performance improvements. It won't cause -Werror to fail and it can be disabled.
Based on #5324 (comment) it would be good if it could appear in annotated html files. However, that's
I'm not sure this is the perfect solution, but I think some kind of diagnostic is necessary to help people with this.