LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
How to Make LISP Go Faster than C
Didier Verna
didier@lrde.epita.fr
http://www.lrde.epita.fr/Ėœdidier
Version 1.4 ā€“ June 13, 2006
1/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Introduction
Myths and legends. . .
ā€LISP is slowā€ . . . NOT ! (itā€™s been 20 years)
Why is LISP fast ?
ī‰
Smart compilers (ā‡’ native machine code)
ī‰
Static typing (types known at compile-time)
ī‰
Safety levels (compiler optimizations)
ī‰
Efļ¬cient data structures (arrays, hash tables etc.)
Demonstration:
ī‰
Comparative C and LISP benchmarks
ī‰
4 simple image processing algorithms
ī‰
Pixel storage and access / arithmetic operations
ā‡’ Equivalent performance
(LISP 10% better in some cases)
2/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Table of contents
1 Experimental Conditions
2 C Programs and Benchmarks
3 LISP code, take 1
4 LISP code, take 2
Typing mechanisms
Optimization
Results
5 Type inference
3/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Experimental conditions
The algorithms: the ā€œpoint-wiseā€ class
ī‰
Pixel assignment / addition / multiplication / division
ī‰
Parameters: image size / type / storage
ī‰
Presented: 800 āˆ— 800 int / float images
The protocol
ī‰
Debian GNU Linux / 2.4.27-2-686 packaged kernel
ī‰
Pentium 4 3GHz / 1GB RAM / 1MB level 2 cache
ī‰
Single user mode / SMP off (no hyperthreading)
ī‰
Measures on 200 consecutive iterations
5/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
C code sample
The add function
void add ( image āˆ— to , image āˆ— from , f lo a t v a l )
{
i n t i ;
const in t n = imaāˆ’>n ;
for ( i = 0 ; i < n ; ++ i )
toāˆ’>data [ i ] = fromāˆ’>data [ i ] + val ;
}
Gcc 4.0.3 (Debian package)
Full optimization: -O3 -DNDEBUG plus inlining
Note: inlining should be almost negligible
7/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Results (seconds)
Time is of the Essence
Fully optimized inlined C code
Algorithm Integer Image Float Image
Assignment 0.29 0.29
Addition 0.48 0.47
Multiplication 0.48 0.46
Division 0.58 1.93
Surprise: integer division should be costly
ā€œConstant Integer Optimizationā€ (with inlining)
Do not neglect inlining !
8/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
First shot at LISP code
CMU-CL 19c (CVS)
The add function, take 1
( defun add ( t o from v al )
( l e t ( ( s i z e ( arrayāˆ’dimension to 0 ) ) )
( dotimes ( i s i z e )
( s etf ( a r e f to i ) (+ ( aref from i ) val ) ) ) ) )
COMMO N-LISPā€™s standard simple-array type
Interpreted version: 2300x
Compiled version: 60x
Optimized version: 20x
Untyped code ā‡’ dynamic type checking !
10/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Typing mechanisms
Typing paradigm:
ī‰
Type information (COMMON-LISP standard)
Declare the expected types of LISP objects
ī‰
Type information is optional
Declare only what you know; give hints to the compilers
ī‰
Both a statically and dynamically typed language
Typing mechanisms:
ī‰
Function arguments:
(make-array size :element-type ā€™single-float)
ī‰
Type declarations:
Function parameter / freshly bound local variable
ī‰
. . .
12/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Typed LISP code sample
Declaring the types of function parameters
The add function, take 2
( defun add ( t o from v al )
( d e c l a r e ( type ( simpleāˆ’array s i n g l e āˆ’f l o a t ( āˆ— ) )
t o from ) )
( d e c l a r e ( type s i n gl e āˆ’ f l o a t v a l ) )
( l e t ( ( s i z e ( arrayāˆ’dimension to 0 ) ) )
( dotimes ( i s i z e )
( s etf ( a r e f to i ) (+ ( aref from i ) val ) ) ) ) )
simple-arrayā€™s . . .
of single-floatā€™s . . .
unidimensional.
13/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Object representation
Why typing matters for performance
Dynamic typing ā‡’ objects of any type (worse: any size)
LISP variables donā€™t carry type information: objects do
The ā€œboxedā€ representation of LISP objects
Type information
Pointer to Lisp Object
Actual value
Dynamic type checking is costly !
Pointer dereferencing is costly !
14/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
The beneļ¬ts of typing
2 examples
Array storage layout:
ī‰
Homogeneous arrays of a known type
ā‡’ native representation usable
ī‰
Specialization of the aref function
ī‰
ā€œOpen Codingā€
Immediate objects:
ī‰
Short (less than a memory word)
ī‰
Special ā€œtag bitsā€ (invalid as pointer values)
ī‰
ā‡’ Encoded inline
Unboxed fixnum representation
00
0
1
Tag bits
Bits 1 ... 29 30 31 32
fixnum value (30 bits)
15/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Example: optimizing a loop index
(dotimes (i 100) ...)
Disassembly of a dotimes macro
58701478: .ENTRY FOO( )
90: POP DWORD PTR [ EBPāˆ’8]
93: LEA ESP, [ EBPāˆ’32]
96: XOR EAX, EAX
98: JMP L1
9A: L0 : ADD EAX, 4
9D: L1 : CMP EAX, 400
A2 : JL L0
A4 : MOV EDX, #x2800000B
A9 : MOV ECX, [ EBPāˆ’8]
AC: MOV EAX , [EBPāˆ’4]
AF: ADD ECX, 2
B2 : MOV ESP, EBP
B4 : MOV EBP, EAX
B6 : JMP ECX
16/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Activating optimization
ā€œQualitiesā€ (COMMON-LISP standard): between 0 and 3
safety, speed etc.
Global or local declarations in source code
(no compiler ļ¬‚ag)
Global qualities declaration
(declaim (optimize (speed 3)
(compilation-speed 0)
(safety 0)
(debug 0)))
Safe code: declarations treated as assertions
Optimized code: declarations trusted
17/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Results
And here comes a little surprise. . .
C and LISP comparative performance
Integer Image Float Image
Algorithm
C LISP C LISP
Assignment 0.29 0.29 0.29 0.29
Addition 0.48 0.48 0.47 0.46
Multiplication 0.48 0.48 0.46 0.45
Division 0.58 1.80 1.93 1.72
Identical performances from C and LISP
C better at integer division
(no ā€œconstant integer optimizationā€ in LISP compilers)
Surprise: LISP 10% faster at ļ¬‚oating-point division
18/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Type inference
Static typing is not as easy as it seems. . .
What to do when not all types are provided ?
ī‰
What about the type of i and size ?
ī‰
What about the type of (
*
fixnum fixnum) ?
ā‡’ Figure out at run-time
ī‰
Stay dynamically typed
ī‰
Use boxed representations
ā‡’ Infer the missing types . . . but
ī‰
Type inference systems of various behavior and quality
ī‰
COMMON-LISP standard too weak about type
declarations
20/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Example of type inference
multiply excerpt
; ; . . .
( d e c l a r e ( type ( simpleāˆ’array fixnum ( āˆ— ) ) to from ) )
( d e c l a r e ( type f ixnum v al ) )
; ; . . .
( s etf ( a r e f to i ) ( the fixnum (āˆ— ( a r e f from i ) va l ) ) ) ) ) )
(
*
fixnum fixnum) ī€¶= fixnum in general . . . but
ī‰
to declared as an array of fixnumā€™s
ī‰
So the multiplication has to return a ļ¬xnum
Sadly, not all type inference systems are that smart
(e.g. Allegro)
ī‰
Need for further explicit type information
ī‰
Type declarations for intermediate values: the
21/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Conclusion
Optimizing LISP code:
data structures, type declarations, optimization
Todayā€™s compilers are smart:
performance can be equivalent to (or better than) C
Typing can be cumbersome
(source code annotation)
Difļ¬cult to provide both correct and minimal information
(weakness of the COMMON-LISP standard)
22/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
Perspectives
Low level: try other compilers / architectures
(and compiler / architecture speciļ¬c optimization
settings)
Medium level: try more sophisticated algorithms
(neighborhoods, front-propagation)
High level: try different levels of genericity
(dynamic object orientation, static meta-programming)
Do not restrict to image processing
23/24
LISP:
faster than C?
Didier Verna
Introduction
Experiments
The case of C
Raw LISP
Typed LISP
Typing mechanisms
Optimization
Results
Type inference
Conclusion
In greater detail. . .
For the interested reader
Beating C in Scientiļ¬c Computing Applications
On the Behavior and Performance of Lisp, Part I.
Verna, D. (2006). In Third European LISP Workshop at
ECOOP, Nantes, France.
http://lisp-ecoop06.bknr.net/.
Logo by Manfred Spiller
24/24