Download presentation
Presentation is loading. Please wait.
Published byJonas Cannon Modified over 9 years ago
1
11 Speed & Debug
2
Lisp is really two languages: A language for writing fast programs A language for writing programs fast In the early stage, you can trade speed for convenience. Then, you can refine critical portions to make them faster once your program begins to crystallize
3
Optimization Should be focused on bottlenecks Should not begin too early Should begin with algorithms Programs tend to have a few bottlenecks that account for a great part of the execution time “Most of the running time in none-IO-bound programs is concentrated in about 3% of the source text. Optimizing these parts of the program will make it run noticeably faster; optimizing the rest of the program will be a waste of time on comparison.”, by Knuth
4
Optimize the program from the top Make sure that you’re using the most efficient algorithm before you resort to low-level coding tricks Decisions about algorithms have to be made early
5
Five parameters control the way your code is compiled Speed: the speed of the code produced by the compiler Compilation-speed: the speed at which your program will be compiled Safety: the amount of error-checking done in the object code Space: the size and memory needs of the object code Debug: the amount of information retained for debugging
6
The compilation parameters are not real variables. They are assigned weights from 0 (unimportant) to 3 (most important) in declarations (defun bottlenect (…) (do (…) (…) (do (…) (…) (declare (optimize (speed 3) (safety 0))) …))) Add such declarations until the code was finished and tested
7
Inline function Without the cost of calling functions Similar to macros Macro ▪ Since macros use mere textual substitution, this may result in unintended side-effects and inefficiency due to re-evaluation of arguments and order of operations ▪ Compiler errors within macros are often difficult to understand, because they refer to the expanded code Recursive functions cannot be inlined If an inlined function is redefined, we have to recompile any function that calls it
8
(declaim (inline single?)) (defun single? (lst) (and (consp lst) (null (cdr lst)))) (defun foo (x) (single? (bar x))) When foo is compiled (defun foo (x) (let ((lst (bar x))) (and (consp lst) (null (cdr lst)))))
9
In most languages, you have to declare the type of each variable, and the variable can only hold values of that type → strongly typed language Common List uses manifest typing (run-time typing) Type information is attached to the data objects Type information is used at run-time Variables can hold objects of any type We have to pay for this flexibility in speed ▪ The function have to look at the types of each of its arguments at run- time If we just want one type, say, fixnum, this is an inefficient way
10
In Common Lisp, type declarations are completely optional Global declarations are made with declaim (declaim (type fixnum *count*)) ;type can be omitted Local declarations are made with declare (defun poly (a b x) (declare (fixnum a b x)) (+ (* a (expt x 2)) (* b x)))
11
Type declarations are particularly important for the contents of complex objects, including arrays and structures Declarations can improve efficiency The compiler can determine the types of arguments to functions and represent these objects more efficients ▪ If nothing is known about the type of elements an array will contain, it has to be represented in memory as a block of pointers ▪ If it is known that the array will only contain, say, double- floats, then the array can be represented as a block of actual double-floats
12
(setf x (vector 1.234d0 2.345d0 3.456d0) y (make-array 3 :element-type ‘double-float) (aref y 0) 1.234d0 (aref y 1) 2.345d0 (aref y 2) 3.456d0)
13
(setf a (make-array ‘(1000 1000) :element-type ‘single-float :initial-element 1.0)) (defun sim-elts (a) (declare (type (simple-array single-float (1000 1000)) a)) (let ((sum 0.0)) (declare (type single-float sum)) (dotimes (r 1000) (dotimes (c 1000) (incf sum (aref a r c)))) sum))
14
> (compile-file “..\\test\\declare.lsp”) > (load “..\\test\\declare.fas”) > (time (sum-elts a)) Real time: 0.823 sec. Run time: 0.8112052 sec. Space: 11999988 Bytes GC: 1, GC time: 0.1092007 sec. 1000000.0 > (compile-file “..\\test\\nodeclare.lsp”) > (load “..\\test\\nodeclare.fas”) > (time (sum-elts-nodeclare a)) Real time: 1.026 sec. Run time: 0.9984064 sec. Space: 11999988 Bytes GC: 2, GC time: 0.2340015 sec. 1000000.0
15
Dynamic allocation is slow Programs that cons a lot tend to run slowly in Lisp implementations with bad garbage collectors Until recently, most Lisp implementations have had bad garbage collectors Efficient programs should cons as little as possible
16
One of the easiest way is to use destructive functions When you know it’s safe to modify a list, you can use delete instead of remove, nreverse instead of reverse, and so on SAFEDESTRUCTIVE append reverse remove remove-if remove-duplicates subst subst-if union intersection set-difference nconc nreverse delete delete-if delete-duplicates nsubst nsubst-if nunion nintersection nset-difference.
17
Use a pre-allocated vector instead of building it using conses > (setf *print-array* t) T > (setf vec (make-array 10 :fill-pointer 2 :initial-element nil)) #(NIL NIL) > (length vec) 2 > (vector-push ‘a vec) 2 > vec #(NIL NIL A) > (vector-pop vec) A > vec #(NIL NIL)
18
svref is more efficient than aref eq is more efficient than eql (reduce #’+ ‘(1 2 3)) is more efficient than (apply #’+ ‘(1 2 3))
19
trace (defun count-atoms (expression) (if (atom expression) 1 (+ (count-atoms (first expression)) (count-atoms (rest expresstion))))) > (count-atoms ‘((this is) (a test))) 7 ;we expect 4
20
> (trace count-atoms) ;; Tracing function COUNT-ATOMS. (COUNT-ATOMS) (count-atoms '((this is) (a test)))
21
2. Trace: (COUNT-ATOMS '((THIS IS) (A TEST))) 3. Trace: (COUNT-ATOMS '(THIS IS)) 4. Trace: (COUNT-ATOMS 'THIS) 4. Trace: COUNT-ATOMS ==> 1 4. Trace: (COUNT-ATOMS '(IS)) 5. Trace: (COUNT-ATOMS 'IS) 5. Trace: COUNT-ATOMS ==> 1 5. Trace: (COUNT-ATOMS 'NIL) 5. Trace: COUNT-ATOMS ==> 1 4. Trace: COUNT-ATOMS ==> 2 3. Trace: COUNT-ATOMS ==> 3 3. Trace: (COUNT-ATOMS '((A TEST))) 4. Trace: (COUNT-ATOMS '(A TEST)) 5. Trace: (COUNT-ATOMS 'A) 5. Trace: COUNT-ATOMS ==> 1 5. Trace: (COUNT-ATOMS '(TEST)) 6. Trace: (COUNT-ATOMS 'TEST) 6. Trace: COUNT-ATOMS ==> 1 6. Trace: (COUNT-ATOMS 'NIL) 6. Trace: COUNT-ATOMS ==> 1 5. Trace: COUNT-ATOMS ==> 2 4. Trace: COUNT-ATOMS ==> 3 4. Trace: (COUNT-ATOMS 'NIL) 4. Trace: COUNT-ATOMS ==> 1 3. Trace: COUNT-ATOMS ==> 4 2. Trace: COUNT-ATOMS ==> 7 7
22
(defun count-atoms (expression) (cond ((atom expression) 1) ((null expression) 0) (t (+ (count-atoms (first expression)) (count-atoms (rest expression)))))) > (count-atoms ‘((this is) (a test))) 7
23
(defun count-atoms (expression) (cond ((null expression) 0) ((atom expression) 1) (t (+ (count-atoms (first expression)) (count-atoms (rest expression)))))) > (count-atoms ‘((this is) (a test))) 4 > (untrace count-atoms)
24
> (dribble “record.txt”) ; 記錄在 toplevel 的過程 … … > (dribble) ;stop dribbling > (ed “record.txt”)
25
Write a Lisp program with at least 15 functions Due June 30 Report Source code Demo
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.