gcl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Gcl-devel] [Axiom-developer] Axiom May 2012 release


From: Camm Maguire
Subject: Re: [Gcl-devel] [Axiom-developer] Axiom May 2012 release
Date: Tue, 12 Jun 2012 16:03:25 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux)

Greetings, and thanks!

BTW, the Debian axiom package automatically polls

http://axiom.axiom-developer.org/axiom-website/download.html

for new releases (in case I miss an email list post), as

http://axiom.axiom-developer.org/axiom-website/downloads/  

is not searchable.  So if you remember to update the former when making
a release, I'll be sure to see it and package updates can proceed more
smoothly. 

u1204 <address@hidden> writes:

> Yes, the src tar is at:
> http://axiom-developer.org/axiom-website/downloads/axiom-may2012-src.tgz
>
> I'd like to know the details for the blas/lapack/atlas FFI
> and also the details of FFI. 
>

You're probably already familiar with the legacy FFI using defentry, as
I think axiom uses this already.  This is a bit slow, but functional.

I've designed a new one with the goal of accessing shared libraries from
within GCL given its unique (it appears) ability to unexec a running
image, and reexec later, possibly on a different machine.  A shared
library link therefore needs to be remembered in the image, together
with all code pointer locations which must be reset on image startup.
The following is implemented in the 2.7.0 tree, but can be backported
rather easily if you need it.

There is a :lib package:

(do-external-symbols (s :lib) (print s))

LIB:|libm| 
LIB:|libc| 

each external symbol of which tracks a live shared library binding, and
which also names another package with the dynamically linked symbols in
use:

COMPILER>(do-external-symbols (s 'lib:|libm|) (print s))

|libm|:|atan| 
|libm|:|ctan| 
|libm|:|csqrt| 
|libm|:|clogf| 
|libm|:|acosh| 
|libm|:|ccosh| 
|libm|:|expf| 
|libm|:|atanhf| 
|libm|:|casin| 
|libm|:|cexpf| 
|libm|:|acosf| 
|libm|:|sqrtf| 
|libm|:|exp| 
|libm|:|atanh| 
|libm|:|ccosf| 
|libm|:|ctanh| 
|libm|:|cosh| 
|libm|:|ccoshf| 
|libm|:|cosf| 
|libm|:|atanf| 
|libm|:|cos| 
|libm|:|cacos| 
|libm|:|tanh| 
|libm|:|ctanf| 
|libm|:|csinhf| 
|libm|:|tanf| 
|libm|:|tan| 
|libm|:|asin| 
|libm|:|sinh| 
|libm|:|csin| 
|libm|:|sinf| 
|libm|:|cabs| 
|libm|:|sin| 
|libm|:|catanhf| 
|libm|:|coshf| 
|libm|:|catanh| 
|libm|:|fabs| 
|libm|:|catanf| 
|libm|:|tanhf| 
|libm|:|acoshf| 
|libm|:|asinh| 
|libm|:|csinh| 
|libm|:|asinhf| 
|libm|:|atan2f| 
|libm|:|asinf| 
|libm|:|sinhf| 
|libm|:|atan2| 
|libm|:|csinf| 
|libm|:|cabsf| 
|libm|:|fabsf| 
|libm|:|casinhf| 
|libm|:|logf| 
|libm|:|casinh| 
|libm|:|clog| 
|libm|:|casinf| 
|libm|:|ctanhf| 
|libm|:|csqrtf| 
|libm|:|log| 
|libm|:|cacoshf| 
|libm|:|cacosh| 
|libm|:|catan| 
|libm|:|cacosf| 
|libm|:|cexp| 
|libm|:|acos| 
|libm|:|sqrt| 
|libm|:|ccos| 

Each of these symbols name genuine lisp functions which wrap calls to
the external routine in question:

(function-lambda-expression #'|libm|:|atan| )

(LAMBDA (#:G550) (DECLARE (OPTIMIZE (SAFETY 2)))
        (CHECK-TYPE #:G550 (LONG-FLOAT * *))
        (BLOCK |libm|:|atan| (CADD-DLADDRESS "dlatan" |libm|:|atan|)
               (LIT :DOUBLE "(" "(double(*)(double))" "(" "dlatan"
                    "))(" (:DOUBLE #:G550) "" ")")))
NIL
|libm|:|atan|


These functions check argument types, but when inlined at (default)
safety 0, simply compile to calls to the routine through a C pointer. 

COMPILER>(disassemble '|libm|:|atan| nil)

;; Compiling /tmp/gazonk_21018_0.lsp.
;; End of Pass 1.  
;; End of Pass 2.  
;; OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3, 
(Debug quality ignored)
;; Finished compiling /tmp/gazonk_21018_0.o.

#include "gazonk_21018_0.h"
void init_code(){do_init((void *)VV);}
/*      local entry for function libm::atan     */

static object LI1__atan___gazonk_21018_0(object V2)
{        VMB1 VMS1 VMV1
        if(!(type_of((V2))==t_longfloat)){
        goto T4;}
        goto T3;
        goto T4;
T4:;
        V2= (VFUN_NARGS=4,/* SYSTEM::CHECK-TYPE-SYMBOL 
*/(*LnkLI2)(((object)VV[1]),(V2),((object)VV[2]),Cnil));
        goto T3;
T3:;
        {object V3 = make_longfloat(((double(*)(double))(dlatan))(lf(V2)));
        VMR1(V3);}
}


COMPILER>(declaim (inline |libm|:|atan|))

NIL

COMPILER>(disassemble '(lambda (x) (declare (long-float x)) (|libm|:|atan| x)) 
nil)

;; Compiling /tmp/gazonk_21018_0.lsp.
;; End of Pass 1.  
;; End of Pass 2.  
;; OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3, 
(Debug quality ignored)
;; Finished compiling /tmp/gazonk_21018_0.o.

#include "gazonk_21018_0.h"
void init_code(){do_init((void *)VV);}
/*      local entry for function COMPILER::CMP-ANON     */

static object LI1__CMP_ANON___gazonk_21018_0(object V2)
{        VMB1 VMS1 VMV1
        {object V3 = make_longfloat(((double(*)(double))(dlatan))(lf(V2)));
        VMR1(V3);}
}


New bindings are made via the defdlfun macro:

(defdlfun (:double "cblas_ddot" "libcblas.so") :int :double* :int :double* :int)

|libcblas|:|cblas_ddot|

(do-external-symbols (s :lib) (print s))

LIB:|libcblas| 
LIB:|libm| 
LIB:|libc| 
NIL

(do-external-symbols (s :|libcblas|) (print s))

|libcblas|:|cblas_ddot| 
NIL


The usage exactly follows C prototype rules.   

One limitation at present is that the function cannot be run when
interpreted, i.e. must be compiled.  I'll try to find time to fix this:

(compile '|libcblas|:|cblas_ddot| )

;; Compiling /tmp/gazonk_21018_0.lsp.
;; End of Pass 1.  
;; End of Pass 2.  
;; OPTIMIZE levels: Safety=0 (No runtime error checking), Space=0, Speed=3, 
(Debug quality ignored)
;; Finished compiling /tmp/gazonk_21018_0.o.
;; Loading /tmp/gazonk_21018_0.o
start address -T 0xb66b50 ;; Finished loading /tmp/gazonk_21018_0.o
#<function 01cf2090>
NIL
NIL

The function can now be used as any other function:

(setq a (make-array 10 :element-type 'long-float :static t
:initial-contents '(1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0)))

#(1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0)

(|libcblas|:|cblas_ddot| 10 a 1 a 1)

385.0

When the image is saved and restarted, the linking pointer is
automatically updated.

(si::save-system "ff")
address@hidden:~/debian/gcl/gclcvs/tmp/unixport$ ./ff
GCL (GNU Common Lisp)  NIL.NIL.NIL CLtL1    May 25 2012 14:58:14
Source License: LGPL(gcl,gmp,pargcl), GPL(unexec,bfd,xgcl)
Binary License:  GPL due to GPL'ed components: (XGCL READLINE UNEXEC)
Modifications of this banner must retain notice of a compatible license
Dedicated to the memory of W. Schelter

Use (help) to get some basic information on how to use GCL.

Temporary directory for compiler files set to /tmp/

>(in-package :compiler)

#<"COMPILER" package>

COMPILER>(|libcblas|:|cblas_ddot| 10 a 1 a 1)

385.0

COMPILER>


On Debian based systems, such blas calls automatically proceed to
optimized atlas calls (when installed) making use of specialized vector
instruction extensions.

One thing that should be kept in mind when using blas/lapack/atlas is
that the latter can call malloc under certain circumstances.  I wish
these libraries had some means to toggle allocation on the stack, but
they don't, or at least didn't last time I looked.  This means that if
you pass arrays allocated in relocatable memory, the result could be
corrupted if a gc is triggered.  We wrote gmp wrappers to handle a
similar situation.  But for a generic interface, this is impossible, so
arrays should be allocated in contiguous block memory to be safe,
i.e. using the :static t keywords in make-array.  It is somewhat of a
pity, as such memory is slower to GC.


If you have any questions, please feel free.


Take care,

> Tim
>
>
>
>

-- 
Camm Maguire                                        address@hidden
==========================================================================
"The earth is but one country, and mankind its citizens."  --  Baha'u'llah



reply via email to

[Prev in Thread] Current Thread [Next in Thread]