(incf x) slower than (setf x (+ x 1))?

Discussion of Common Lisp

(incf x) slower than (setf x (+ x 1))?

Postby sylwester » Fri Aug 19, 2011 5:46 pm

I'm testing in GNU CLISP. I havent tried sbcl or others (yet)
Without testing I have used incf and decf since I htough it would be a optimization. Today I benchmarked a little and found out incf performes 3 times slower than setf.
For me this doesn't make any sense. Why do we have incf/decf if not for speed?


Code: Select all
[7]> (time (dotimes (n 10000) (setf test (+ 1 test))))
Real time: 0.055758 sec.
Run time: 0.056004 sec.
Space: 400840 Bytes
GC: 1, GC time: 0.012 sec.
NIL
[8]> (time (dotimes (n 10000) (setf test (1+ test))))
Real time: 0.042886 sec.
Run time: 0.040002 sec.
Space: 400840 Bytes
NIL
[9]> (time (dotimes (n 10000) (incf test 1)))
Real time: 0.152384 sec.
Run time: 0.152009 sec.
Space: 3040840 Bytes
GC: 4, GC time: 0.028002 sec.
NIL
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p
sylwester
 
Posts: 83
Joined: Mon Jul 11, 2011 2:53 pm

Re: (incf x) slower than (setf x (+ x 1))?

Postby Duke » Fri Aug 19, 2011 6:07 pm

sylwester wrote:I'm testing in GNU CLISP. I havent tried sbcl or others (yet)
Without testing I have used incf and decf since I htough it would be a optimization. Today I benchmarked a little and found out incf performes 3 times slower than setf.
For me this doesn't make any sense. Why do we have incf/decf if not for speed?[/code]

We don't have it for speed. INCF wraps SETF, to put it simply, and I'd have to figure that SETF compiles more or less directly to a MOV opcode anyway, so you're not going to top SETF for efficiency. Rather, INCF exists for convenience. I'm guessing that INCF is slower in CLISP because CLISP has to do so much consing... That is what it means by "space" isn't it?

You might find the output of these expressions interesting:

CL-USER> (let ((bork 0)) (disassemble #'(lambda () (setf bork (1+ bork)))))
CL-USER> (let ((bork 0)) (disassemble #'(lambda () (incf bork))))

Also: define-modify-macro
"If you want to improve, be content to be thought foolish and stupid." -Epictetus
Duke
 
Posts: 38
Joined: Sat Oct 17, 2009 10:40 pm

Re: (incf x) slower than (setf x (+ x 1))?

Postby saulgoode » Fri Aug 19, 2011 6:26 pm

sylwester wrote:Why do we have incf/decf if not for speed?

For code readability/conciseness?

Try writing the 'setf' equivalent to
    (incf (aref myarray (incf indx)))
saulgoode
 
Posts: 45
Joined: Tue Dec 14, 2010 1:39 am

Re: (incf x) slower than (setf x (+ x 1))?

Postby Ramarren » Sat Aug 20, 2011 12:16 am

sylwester wrote:For me this doesn't make any sense. Why do we have incf/decf if not for speed?


CLISP is an interpreter, and when executed from the REPL the expressions appears to be fully interpreted, that is, INCF is expanded inside the loop, which obviously costs time and space. If you wrap the operations in a function the time difference disappears, and you can see using DISASSEMBLE that they emit the same code.
Ramarren
 
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland

Re: (incf x) slower than (setf x (+ x 1))?

Postby sylwester » Sun Aug 21, 2011 2:12 pm

So I was fooled by the interprenter repl. Since I prefer incf I'll continue with it and for the future I'll make compiled functions out of my benchmarks :)
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p
sylwester
 
Posts: 83
Joined: Mon Jul 11, 2011 2:53 pm

Re: (incf x) slower than (setf x (+ x 1))?

Postby huangho » Mon Aug 22, 2011 4:09 pm

In compiled code, there is no difference:
Code: Select all
[8]> (defun f () (let ((test 0)) (dotimes (i 10000) (incf test))))
f
[9]> (defun g () (let ((test 0)) (dotimes (i 10000) (setf test (+ test 1)))))
g
[10]> (compile 'f)
f ;
nil ;
nil
[11]> (compile 'g)
g ;
nil ;
nil
[12]> (time (f))
Real time: 0.001149 sec.
Run time: 0.0 sec.
Space: 0 Bytes
nil
[13]> (time (f))
Real time: 0.001147 sec.
Run time: 0.004001 sec.
Space: 0 Bytes
nil
[14]> (time (g))
Real time: 0.00115 sec.
Run time: 0.004 sec.
Space: 0 Bytes
nil
[15]> (time (g))
Real time: 0.001142 sec.
Run time: 0.004 sec.
Space: 0 Bytes
nil

Indeed, (incf x) expands into a setf form (actually setq, but setf also expands into a setq):
Code: Select all
[16]> (macroexpand '(incf x))
(setq x (+ x 1)) ;
t
[17]> (macroexpand '(setf x (+ x 1)))
(setq x (+ x 1)) ;
t
huangho
 
Posts: 3
Joined: Fri Sep 03, 2010 5:15 pm
Location: Porto Alegre, Brazil


Return to Common Lisp

Who is online

Users browsing this forum: No registered users and 1 guest

cron