Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp, asdf, tests, compile system with different optimization levels

What I really want is the in-source tests definitions:

Let's suppose I have an asdf system:

(defsystem simple-system
  :serial t
  :components ((:module "src"
                        :components
                        ((:file "0-package")
                         (:file "1-tests-stubs")
                         (:file "2-code") ...))))

And another system to test the first:

(defsystem simple-system-tests
  :serial t
  :components ((:module "src"
                        :components
                        ((:file "0-package")
                         (:file "1-tests-real")
                         (:file "2-code") ...))))

The only difference between them is that in the simple-system I have 1-tests-stubs where in the simple-system-tests I have 1-tests-real. In 1-tests-stubs I define a macro (defmacro def-test (&rest _args) nil) which gets a 'real' implementation in the 1-tests-real.

Now I want to compile the simple-system with (declare (optimize (safety 0) (debug 0) (speed 3))) and the simple-system-tests with the opposite (declare (optimize (safety 3) (debug 3) (speed 0))).

How can I do that(where to put and how to set these declarations in a generic way for these two systems)?

How can I reuse the definition of simple-system in the simple-system-tests (not to repeat myself retyping all modules/components)?

And I must be sure that all files are recompiled with different optimization levels for each system.

Also, it would be great if for each system files will be recompiled only if they were changed(Own copy of compiled files for each system?).

like image 794
Bad_ptr Avatar asked Mar 08 '23 07:03

Bad_ptr


2 Answers

Optimization with low safety.

Generally I would not recommend to compile a whole system (a library or application) with zero safety like this:

(declare (optimize (safety 0) (debug 0) (speed 3)))

Using zero safety in combination to type declarations may alter semantics of the program and errors may crash the program. It might even open up security holes.

My recommendation for production code is this:

  • optimize speed critical parts with speed = 3 and leave the usual safety settings (2 or 3).

  • if a low safety setting then is needed for even further speed improvements, declare it only where it is needed. Common Lisp provides function local declarations and also a special operator locally where one further can restrict the code area where declarations apply.

Making optimization settings changeable

* (defparameter *safety* 0)

This does not work, because safety values need to be numbers:

*SAFETY*
* (defun foo (a) (declare (optimize (safety *safety*))) (1+ a))
; in: DEFUN FOO
;     (OPTIMIZE (SAFETY *SAFETY*))
; 
; caught WARNING:
;   Ignoring bad optimization value *SAFETY* in: (OPTIMIZE (SAFETY *SAFETY*))
; 
; compilation unit finished
;   caught 1 WARNING condition

FOO

But this works, using read-time evaluation:

* (defun foo (a) (declare (optimize (safety #.*safety*))) (1+ a))
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN

FOO

One can also insert whole declarations:

* (defparameter *optimization-declaration* '(declare (optimize (safety 0))))

*OPTIMIZATION-DECLARATION*
* (defun foo (a) #.*optimization-declaration* (1+ a))
WARNING: redefining COMMON-LISP-USER::FOO in DEFUN

FOO
* 
like image 143
Rainer Joswig Avatar answered Apr 28 '23 11:04

Rainer Joswig


 Optimization levels

You can try using :around-compile:

(defsystem simple-system
  :serial t
  :around-compile (lambda (next)
                    (proclaim '(optimize (debug 3) 
                                         (safety 3)
                                         (debug 3)
                                         (speed 0)))
                    (funcall next))
  :components ((:module "src"
                        :components
                        (...))))

The documentation says (emphasis mine):

Using this hook, you may achieve such effects as: locally renaming packages, binding *readtables* and other syntax-controlling variables, handling warnings and other conditions, proclaiming consistent optimization settings, saving code coverage information, maintaining meta-data about compilation timings, setting gensym counters and PRNG seeds and other sources of non-determinism, overriding the source-location and/or timestamping systems, checking that some compile-time side-effects were properly balanced, etc.

The action is performed around each file that is being compiled in the system; you can shadow the value of :around-compile for all files in a module, or specific files.

like image 24
coredump Avatar answered Apr 28 '23 11:04

coredump