Negative tuple elements produce inefficient code. #55453
Copy link
Copy link
Closed
Labels
performancePerformance or resource usagePerformance or resource usage
Description
| BPO | 11244 |
|---|---|
| Nosy | @rhettinger, @mdickinson, @pitrou, @bitdancer, @eltoder |
| Files |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/mdickinson'
closed_at = <Date 2011-03-23.18:20:49.447>
created_at = <Date 2011-02-18.17:41:04.894>
labels = ['performance']
title = 'Negative tuple elements produce inefficient code.'
updated_at = <Date 2011-03-23.18:20:49.446>
user = 'https://bugs.python.org/jdharper'bugs.python.org fields:
activity = <Date 2011-03-23.18:20:49.446>
actor = 'mark.dickinson'
assignee = 'mark.dickinson'
closed = True
closed_date = <Date 2011-03-23.18:20:49.447>
closer = 'mark.dickinson'
components = []
creation = <Date 2011-02-18.17:41:04.894>
creator = 'jdharper'
dependencies = []
files = ['20787', '20790', '20897', '21073', '21083']
hgrepos = []
issue_num = 11244
keywords = ['patch']
message_count = 28.0
messages = ['128795', '128801', '128805', '128806', '128809', '128810', '128812', '128817', '128825', '128841', '128844', '128876', '129429', '129430', '130529', '130550', '130576', '130579', '130582', '130583', '130640', '130641', '130642', '130665', '131068', '131069', '131901', '131902']
nosy_count = 9.0
nosy_names = ['rhettinger', 'mark.dickinson', 'pitrou', 'nadeem.vawda', 'Arfrever', 'r.david.murray', 'jdharper', 'python-dev', 'eltoder']
pr_nums = []
priority = 'high'
resolution = None
stage = 'commit review'
status = 'closed'
superseder = None
type = 'performance'
url = 'https://bugs.python.org/issue11244'
versions = ['Python 3.1', 'Python 3.2', 'Python 3.3']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
performancePerformance or resource usagePerformance or resource usage
Activity
jdharper commentedon Feb 18, 2011
In Python 3.2, a tuple like (1,-2,3) will not be optimized into a constants at compile time. The tuple is built at run-time. Earlier versions of Python optimized these tuples at compile time.
Here's an example program.
print ("dis x:")
dis(x)
print()
The compiler in 3.2rc3 produces code for function y() that builds the tuple at run-time while the tuple in x() is optimized at compile time.
C:\tmp>c:\python32\python --version
Python 3.2rc3
C:\tmp>c:\python32\python test.py
dis x:
3 0 LOAD_CONST 4 ((1, 2, 3))
3 RETURN_VALUE
dis y:
4 0 LOAD_CONST 1 (1)
3 LOAD_CONST 4 (-2)
6 LOAD_CONST 3 (3)
9 BUILD_TUPLE 3
12 RETURN_VALUE
However, under 3.1.3, the tuples in both functions are optimized at compile time.
C:\tmp>c:\python31\python test.py
dis x:
3 0 LOAD_CONST 4 ((1, 2, 3))
3 RETURN_VALUE
dis y:
4 0 LOAD_CONST 4 ((1, -2, 3))
3 RETURN_VALUE
Although the compiled code produced 3.2rc3 is correct, it is much slower than the code generated by 3.1.3.
jdharper commentedon Feb 18, 2011
I have also determined that negative elements interfere with the frozenset optimization described in bpo-6690. http://bugs.python.org/issue6690.
Here's an example program:
print ("dis x:")
dis(x)
print()
Running this produces:
C:\tmp>c:\Python32\python.exe test.py
dis x:
3 0 LOAD_FAST 0 (var)
3 LOAD_CONST 4 (frozenset({1, 2, 3}))
6 COMPARE_OP 6 (in)
9 RETURN_VALUE
dis y:
4 0 LOAD_FAST 0 (var)
3 LOAD_CONST 1 (1)
6 LOAD_CONST 4 (-2)
9 LOAD_CONST 3 (3)
12 BUILD_SET 3
15 COMPARE_OP 6 (in)
18 RETURN_VALUE
bitdancer commentedon Feb 18, 2011
I wonder if this has anything to do with bpo-9011?
pitrou commentedon Feb 18, 2011
The culprit is r82043: "Issue bpo-9011: Remove buggy and unnecessary ST->AST compilation code".
pitrou commentedon Feb 18, 2011
The problem is that the "UNARY_NEGATIVE + LOAD_CONST" optimization, which occurs first in bytecode order, inserts a NOP and prevents the tuple optimization to work.
jdharper commentedon Feb 18, 2011
I think r82043 may also explain why 3.1.3 can fold the expression 2 * -3 into -6 while 3.2rc3 cannot.
C:\tmp>c:\Python32\python.exe --version
Python 3.2rc3
C:\tmp>c:\Python32\python.exe test.py
dis y:
3 0 LOAD_CONST 1 (2)
3 LOAD_CONST 3 (-3)
6 BINARY_MULTIPLY
7 POP_TOP
8 LOAD_CONST 0 (None)
11 RETURN_VALUE
C:\tmp>c:\Python31\python.exe --version
Python 3.1.3
C:\tmp>c:\Python31\python.exe test.py
dis y:
3 0 LOAD_CONST 3 (-6)
3 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
pitrou commentedon Feb 18, 2011
Ouch. Obviously test_peephole doesn't have enough tests...
jdharper commentedon Feb 18, 2011
Here's a patch against the version of test_peepholer.py in 3.2rc3. It verifies that expressions like the following are optimized:
3*-4
(1,-2,3)
a in {1,-2,3)
pitrou commentedon Feb 18, 2011
Here is a patch that enables advanced (recursive) constant folding.
Example:
python -c "import dis; f=lambda x: x in {(3*-5)+(-1-6),(1,-2,3)*2,None};dis.dis(f)"
With 3.1:
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 7 (-15)
6 LOAD_CONST 8 (-7)
9 BINARY_ADD
10 LOAD_CONST 10 ((1, -2, 3, 1, -2, 3))
13 LOAD_CONST 11 (None)
16 BUILD_SET 3
19 COMPARE_OP 6 (in)
22 RETURN_VALUE
With 3.2+patch:
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 14 (frozenset({None, -22, (1, -2, 3, 1, -2, 3)}))
6 COMPARE_OP 6 (in)
9 RETURN_VALUE
mdickinson commentedon Feb 19, 2011
Unassigning. I don't think that r82043 is the *real* culprit here; that bugfix just happened to expose a deficiency in the peepholer; one that's already present in other situations:
Antoine, does your patch take care of this case too?
pitrou commentedon Feb 19, 2011
It should. Can you test?
mdickinson commentedon Feb 19, 2011
Ah, you're asking me to actually do some (minimal) work instead of just complaining?
Yep, the patch tests fine over here (OS X 10.6), and fixes the 2*(3*4) case.
8 remaining items
rhettinger commentedon Mar 11, 2011
Eugene's patch looks like a correct fix to the regression. I'll review further in the next couple of days.
Antoine, we need to further discuss your checkin to the peephole optimizer. I believe it was inappropriate.
pitrou commentedon Mar 11, 2011
No, it's orthogonal.
eltoder commentedon Mar 11, 2011
Yes, my patch doesn't fix the regression, only a special case of -0.
mdickinson commentedon Mar 12, 2011
Eugene's new patch looks good to me; +1 on applying it.
Raymond, do you happen to remember why it was necessary to add the zero-check in the first place?
eltoder commentedon Mar 15, 2011
Is anyone reviewing my patch? It's just 1 line long. Should it be moved to another issue? Though, technically, it's needed to address the regression in question: Python 3.1 folds -0, the current code still does not.
pitrou commentedon Mar 15, 2011
Eugene, according to Mark your patch is fine. It just needs someone to commit it. I would personally prefer to let Mark handle it, since he's our specialist in negative zeroes (and other numerical subtleties) ;)
python-dev commentedon Mar 23, 2011
New changeset ead9c1b9f547 by Mark Dickinson in branch 'default':
Issue bpo-11244: Remove outdated peepholer check that was preventing the peepholer from folding -0 and -0.0. Thanks Eugene Toder for the patch.
http://hg.python.org/cpython/rev/ead9c1b9f547
mdickinson commentedon Mar 23, 2011
Fixed in 'default' branch. Note that the regression still exists in 3.2; I'm not sure that it's worth backporting the two fixes.