New submission from Oren Milman:

------------ the current state ------------
long_invert first checks whether v is a single-digit int. If it is, it simply 
does 'return PyLong_FromLong(-(MEDIUM_VALUE(v) + 1));'.
Otherwise, long_invert does (edited for brevity) 'x = long_add(v, 
PyLong_FromLong(1));', and then negates x in-place.

In other words, long_invert assumes long_add hasn't returned a reference to an 
element of small_ints.
However, if all of the following conditions are true:
    * NSMALLNEGINTS is maximized (i.e. NSMALLNEGINTS == 2 ** PyLong_SHIFT - 1).
    * long_add is changed in such a way that if someone does (in Python) '-2 ** 
PyLong_SHIFT + 1' while NSMALLNEGINTS is maximized, long_add would return a 
reference to an element of small_ints. (Actually, I have recently opened an 
issue that proposes such a change - http://bugs.python.org/issue27145.)
    * long_invert is called for (-2 ** PyLong_SHIFT).
Then long_invert would negate in-place an element of small_ints.

In addition, because long_invert first checks whether v is a single-digit int, 
calling maybe_small_long before returning would save up memory only in case 
both of the following conditions are true:
    * NSMALLPOSINTS is maximized (i.e. NSMALLPOSINTS == 2 ** PyLong_SHIFT).
    * long_invert is called for (-2 ** PyLong_SHIFT).
So the call to maybe_small_long introduces a performance penalty for every case 
where v is a multiple-digit int (and long_invert doesn't fail), while the only 
case where it actually saves up memory is the aforementioned corner case.


------------ the proposed changes ------------
Both of the proposed changes are in Objects/longobject.c in long_invert:
    1. Replace the in-place negation with a call to _PyLong_Negate, which 
safely negates an int. 
    
    2. Remove the call to maybe_small_long.

    maybe_small_long was added to long_invert in revision 48567, as part of an 
effort to wipe out different places in the code where small_ints could be used 
(and saved up memory), but was not. I am not sure why maybe_small_long was also 
added to long_invert back then, even though it mostly undermines performance.


------------ diff ------------
The patches diff is attached.


------------ tests ------------
I built the patched CPython for x86, and played with it a little. Everything 
seemed to work as usual. 

In addition, I ran 'python_d.exe -m test -j3' (on my 64-bit Windows 10) with 
and without the patches, and got quite the same output.
the outputs of both runs are attached.

----------
components: Interpreter Core
files: proposedPatches.diff
keywords: patch
messages: 267244
nosy: Oren Milman
priority: normal
severity: normal
status: open
title: a potential future bug and an optimization that mostly undermines 
performance in long_invert
type: performance
Added file: http://bugs.python.org/file43186/proposedPatches.diff

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue27214>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to