Tim made me do it! 

 http://groups.google.com/group/comp.lang.python/msg/9075a3bc59c334c9

For whatever reason, I was just curious how his code could be sped up.
 I kept seeing this append method being called and I thought, "there's
an opcode for that."  What happens if you replace var.append() with
the LIST_APPEND opcode.

# standard opcodes
$ ./python ./Lib/timeit.py -n 1000 -s 'import foo' 'foo.foo1(10000)'
1000 loops, best of 3: 3.66 msec per loop
# hacked version
$ ./python ./Lib/timeit.py -n 1000 -s 'import foo' 'foo.foo2(10000)'
1000 loops, best of 3: 1.74 msec per loop

The patch and foo.py are attached.

This code doesn't really work in general.  It assumes that any append
function call is a list method, which is obviously invalid.  But if a
variable is known to be a list (ie, local and assigned as list
(BUILD_LIST) or a list comprehension), could we do something like this
as a peephole optimization?  I'm not familiar enough with some dynamic
tricks to know if it there are conditions that could break this.

Probably useless, but it was interesting to me at the time.

n
Index: Python/compile.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v
retrieving revision 2.352
diff -w -u -r2.352 compile.c
--- Python/compile.c	3 Aug 2005 18:33:05 -0000	2.352
+++ Python/compile.c	14 Sep 2005 05:33:29 -0000
@@ -754,6 +754,37 @@
 			}
 			break;
 
+		/* Replace LOAD_ATTR "append" ... CALL_FUNCTION 1 with
+		   LIST_APPEND */
+		case LOAD_ATTR:
+			/* for testing: only do optimization if name is speed */
+			name = PyString_AsString(PyTuple_GET_ITEM(names, 0));
+			if (name == NULL  ||  strcmp(name, "speed") != 0)
+				continue;
+			/* end testing bit */
+
+			j = GETARG(codestr, i);
+			name = PyString_AsString(PyTuple_GET_ITEM(names, j));
+			if (name == NULL  ||  strcmp(name, "append") != 0)
+				continue;
+			if (i + 9 > codelen)
+				continue;
+			if (codestr[i+6] != CALL_FUNCTION &&
+			    codestr[i+9] != POP_TOP)
+				continue;
+
+			codestr[i+0] = NOP;
+			codestr[i+1] = NOP;
+			codestr[i+2] = NOP;
+			/* 0-2= LOAD_XXX */
+			/* replace CALL_FUNCTION 1 with LIST_APPEND */
+			codestr[i+6] = LIST_APPEND;
+			codestr[i+7] = NOP;
+			codestr[i+8] = NOP;
+			/* get rid of POP_TOP */
+			codestr[i+9] = NOP;
+			break;
+
 		/* Skip over LOAD_CONST trueconst  JUMP_IF_FALSE xx  POP_TOP */
 		case LOAD_CONST:
 			cumlc = lastlc + 1;

def foo1(n):
  d = []
  for x in range(n):
    d.append(5)

def foo2(n):
  speed = []
  for x in range(n):
    speed.append(5)

if __name__ == '__main__':
  import dis
  dis.dis(foo1)
  print
  dis.dis(foo2)
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to