Peter Siebel - Practical Common Lisp

Здесь есть возможность читать онлайн «Peter Siebel - Practical Common Lisp» весь текст электронной книги совершенно бесплатно (целиком полную версию без сокращений). В некоторых случаях можно слушать аудио, скачать через торрент в формате fb2 и присутствует краткое содержание. Год выпуска: 2005, ISBN: 2005, Издательство: Apress, Жанр: Программирование, на английском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале библиотеки ЛибКат.

Practical Common Lisp: краткое содержание, описание и аннотация

Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Practical Common Lisp»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.

Practical Common Lisp — читать онлайн бесплатно полную книгу (весь текст) целиком

Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Practical Common Lisp», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

(defparameter *timing-data* ())

(defmacro with-timing (label &body body)

(with-gensyms (start)

`(let ((,start (get-internal-run-time)))

(unwind-protect (progn ,@body)

(push (list ',label ,start (get-internal-run-time)) *timing-data*)))))

(defun clear-timing-data ()

(setf *timing-data* ()))

(defun show-timing-data ()

(loop for (label time count time-per %-of-total) in (compile-timing-data) do

(format t "~3d% ~a: ~d ticks over ~d calls for ~d per.~%"

%-of-total label time count time-per)))

(defun compile-timing-data ()

(loop with timing-table = (make-hash-table)

with count-table = (make-hash-table)

for (label start end) in *timing-data*

for time = (- end start)

summing time into total

do

(incf (gethash label timing-table 0) time)

(incf (gethash label count-table 0))

finally

(return

(sort

(loop for label being the hash-keys in timing-table collect

(let ((time (gethash label timing-table))

(count (gethash label count-table)))

(list label time count (round (/ time count)) (round (* 100 (/ time total))))))

#'> :key #'fifth))))

This profiler lets you wrap a with-timingaround any form; each time the form is executed, the time it starts and the time it ends are recorded, associating with a label you provide. The function show-timing-datadumps out a table showing how much time was spent in different labeled sections of code like this:

CL-USER> (show-timing-data)

84% BAR: 650 ticks over 2 calls for 325 per.

16% FOO: 120 ticks over 5 calls for 24 per.

NIL

You could obviously make this profiling code more sophisticated in many ways. Alternatively, your Lisp implementation most likely provides its own profiling tools, which, since they have access to the internals of the implementation, can get at information not necessarily available to user-level code.

Once you've found the bottleneck in your code, you can start tuning. The first thing you should try, of course, is to find a more efficient basic algorithm—that's where the big gains are to be had. But assuming you're already using an appropriate algorithm, then it's down to code bumming —locally optimizing the code so it does absolutely no more work than necessary.

The main tools for code bumming in Common Lisp are its optional declarations. The basic idea behind declarations in Common Lisp is that they're used to give the compiler information it can use in a variety of ways to generate better code.

For a simple example, consider this Common Lisp function:

(defun add (x y) (+ x y))

I mentioned in Chapter 10 that if you compare the performance of this function Lisp to the seemingly equivalent C function:

int add (int x, int y) { return x + y; }

you'll likely find the Common Lisp version to be quite a bit slower, even if your Common Lisp implementation features a high-quality native compiler.

That's because the Common Lisp version is doing a lot more—the Common Lisp compiler doesn't even know that the values of aand bare numbers and so has to generate code to check at runtime. And once it determines they are numbers, it has to determine what types of numbers—integers, rationals, floating point, or complex—and dispatch to the appropriate addition routine for the actual types. And even if aand bare integers—the case you care about—then the addition routine has to account for the possibility that the result may be too large to represent as a fixnum , a number that can be represented in a single machine word, and thus it may have to allocate a bignum object.

In C, on the other hand, because the type of all variables are declared, the compiler knows exactly what kind of values aand bwill hold. And because C's arithmetic simply overflows when the result of an addition is too large to represent in whatever type is being returned, there's no checking for overflow and no allocation of a bignum object to represent the result when the mathematical sum is too large to fit in a machine word.

Thus, while the behavior of the Common Lisp code is much more likely to be mathematically correct, the C version can probably be compiled down to one or two machine instructions. But if you're willing to give the Common Lisp compiler the same information the C compiler has about the types of arguments and return values and to accept certain C-like compromises in terms of generality and error checking, the Common Lisp function can also be compiled down to an instruction or two.

That's what declarations are for. The main use of declarations is to tell the compiler about the types of variables and other expressions. For instance, you could tell the compiler that the arguments to addare both fixnums by writing the function like this:

(defun add (x y)

(declare (fixnum x y))

(+ x y))

The DECLARE expression isn't a Lisp form; rather, it's part of the syntax of the DEFUN and must appear before any other code in the function body. [328] Declarations can appear in most forms that introduce new variables, such as LET , LET* , and the DO family of looping macros. LOOP has its own syntax for declaring the types of loop variables. The special operator LOCALLY , mentioned in Chapter 20, does nothing but create a scope in which you can make declarations. This declaration declares that the arguments passed for the parameters xand ywill always be fixnums. In other words, it's a promise to the compiler, and the compiler is allowed to generate code on the assumption that whatever you tell it is true.

To declare the type of the value returned, you can wrap the form (+ x y)in the THE special operator. This operator takes a type specifier, such as FIXNUM , and a form and tells the compiler the form will evaluate to the given type. Thus, to give the Common Lisp compiler all the information about addthat the C compiler gets, you can write it like this:

(defun add (x y)

(declare (fixnum x y))

(the fixnum (+ x y)))

However, even this version needs one more declaration to give the Common Lisp compiler the same license as the C compiler to generate fast but dangerous code. The OPTIMIZE declaration is used to tell the compiler how to balance five qualities: the speed of the code generated; the amount of runtime error checking; the memory usage of the code, both in terms of code size and runtime memory usage; the amount of debugging information kept with the code; and the speed of the compilation process. An OPTIMIZE declaration consists of one or more lists, each containing one of the symbols SPEED , SAFETY , SPACE , DEBUG , and COMPILATION-SPEED , and a number from zero to three, inclusive. The number specifies the relative weighting the compiler should give to the corresponding quality, with 3being the most important and 0meaning not important at all. Thus, to make Common Lisp compile addmore or less like a C compiler would, you can write it like this:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Похожие книги на «Practical Common Lisp»

Представляем Вашему вниманию похожие книги на «Practical Common Lisp» списком для выбора. Мы отобрали схожую по названию и смыслу литературу в надежде предоставить читателям больше вариантов отыскать новые, интересные, ещё непрочитанные произведения.


Отзывы о книге «Practical Common Lisp»

Обсуждение, отзывы о книге «Practical Common Lisp» и просто собственные мнения читателей. Оставьте ваши комментарии, напишите, что Вы думаете о произведении, его смысле или главных героях. Укажите что конкретно понравилось, а что нет, и почему Вы так считаете.

x