From: plamen
Subject: Re Profiling Lisp code
Date: 
Message-ID: <c10ab1d8.0412071039.6570ec54@posting.google.com>
>Note: This is not a quest for the fastest cross product.. rather the
>quest for the better storage method. 

Depending on the application, it may be important not only to have a
fast storage model for your intermediate calculations, but also to
thing about what you do with the results. The cost of getting them out
of Lisp could be also high. If they get sent to something like OpenGL
for example (which I suppose is not very off topic for you), you would
than  consider using arrays, because the array is the very fundamntal
type of OpenGL (for which the pipelines are optimized) and if your CL
implementation allows you to share your Lisp arrays with the foreign
world (as LispWorks for example does), you skip the need to translate
your internal storage representation to that of OpenGL, which, again
depending on the appication, could spare you a lot. In such case you
can of course add some macros to make the arrays look like structures.

Regards
Plamen Stamov

From: Wade Humeniuk
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <xXmtd.50165$VL6.37461@clgrps13>
plamen wrote:

> depending on the appication, could spare you a lot. In such case you
> can of course add some macros to make the arrays look like structures.

It is easier than that:

CL-USER 12 > (defstruct (v3 (:type (vector double-float 3)))
               x y z)
V3

CL-USER 13 > (setf v1 (make-v3 :x 0.1 :y 3.4 :z 6.0))
#(0.1 3.4 6.0)

CL-USER 14 > (v3-x v1)
0.1

CL-USER 15 > (type-of v1)
(SIMPLE-ARRAY DOUBLE-FLOAT (3))


Wade
From: Jeff
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <CWrtd.157462$5K2.74014@attbi_s03>
Wade Humeniuk wrote:

> plamen wrote:
> 
> > depending on the appication, could spare you a lot. In such case you
> > can of course add some macros to make the arrays look like
> > structures.
> 
> It is easier than that:
> 
> CL-USER 12 > (defstruct (v3 (:type (vector double-float 3)))
>                x y z)
> V3
> 

Sweeeeet! Every day, a little something new :)

Jeff M.

-- 
http://www.retrobyte.org
··············@gmail.com
From: Jeff
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <WHcud.738823$8_6.482760@attbi_s04>
Wade Humeniuk wrote:

> (defstruct (v3 (:type (vector double-float 3))) x y z)

While this is very nice, and has simplified quite a bit, I am having
one problem with it. I can't use svref. I can't seem to declare v3 as a
simple-vector instead of a simple-array.

Any suggestions?

Jeff M.

-- 
http://www.retrobyte.org
··············@gmail.com
From: Wade Humeniuk
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <gokud.17003$U47.2083@clgrps12>
Jeff wrote:
> Wade Humeniuk wrote:
> 
> 
>>(defstruct (v3 (:type (vector double-float 3))) x y z)
> 
> 
> While this is very nice, and has simplified quite a bit, I am having
> one problem with it. I can't use svref. I can't seem to declare v3 as a
> simple-vector instead of a simple-array.
> 
> Any suggestions?
> 

As Adam said simple-vectors need an element-type of true.  You
have to use aref (or in this case, just use the structure accessors)

As was mentioned in a previous post, LW allows one to
to pass a pointer to Lisp arrays directly to a Foreign Function.
One just has to allocate the Lisp Object Statically.  I was
interested in this behaviour, so I wrote up some
experimental code.  This type of use would allow
direct sharing of double-float arrays between Lisp
and C.

As an example (in LW):

(defstruct (dfv3 (:type (vector double-float))
                  (:constructor dfv3 (x y z)))
   (x 0d0)
   (y 0d0)
   (z 0d0))

(deftype dfv3 () '(vector double-float 3))

(defun static-dfv3 (x y z)
   (sys:in-static-area (dfv3 x y z)))

;; Simulate a C function to reference a C double[3]
(fli:define-foreign-callable ("getLispArray" :result-type :double)
     ((array (:c-array :double 3))
      (index :int))
   (fli:foreign-aref array index))

;; Simulate a C function to set an element of a C double[3]
(fli:define-foreign-callable ("setLispArray" :result-type :double)
     ((array (:c-array :double 3))
      (index :int)
      (new-value :double))
   (setf (fli:foreign-aref array index) new-value))

(fli:define-foreign-function (cdfv3ref "getLispArray")
     ((array :lisp-array)
      (index :int))
   :result-type :lisp-double-float)

(fli:define-foreign-function (set-cdfv3ref "setLispArray")
     ((array :lisp-array)
      (index :int)
      (new-value :lisp-double-float))
   :result-type :lisp-double-float)

CL-USER 26 > (setf v (static-dfv3 3.4 6.7 8.1))
#(3.4 6.7 8.1)

CL-USER 27 > (cdfv3ref v 0)
3.4

CL-USER 28 > (aref v 0)
3.4

CL-USER 29 > (set-cdfv3ref v 0 10.234)
10.234

CL-USER 30 > (aref v 0)
10.234

CL-USER 31 > (cdfv3ref v 0)
10.234

CL-USER 32 >

Wade
From: Adam Warner
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <pan.2004.12.10.11.38.50.713544@consulting.net.nz>
Hi Jeff,

>> (defstruct (v3 (:type (vector double-float 3))) x y z)
> 
> While this is very nice, and has simplified quite a bit, I am having
> one problem with it. I can't use svref. I can't seem to declare v3 as a
> simple-vector instead of a simple-array.

That's because SIMPLE-VECTORS can only be of type T:
<http://www.lispworks.com/reference/HyperSpec/Body/t_smp_ve.htm>

BTW the above syntax is incorrect (no num. elements specified):
<http://www.lispworks.com/reference/HyperSpec/Body/m_defstr.htm>

   (vector element-type)

   The structure is represented as a (possibly specialized) vector,
   storing components as vector elements. Every component must be of a
   type that can be stored in a vector of the type specified. The first
   component is vector element 1 if the structure is :named, and element
   0 otherwise. The structure can be :named only if the type symbol is a
   subtype of the supplied element-type.

I'd also avoid making default slots a type violation (NIL is not of type
DOUBLE-FLOAT). Fixing these two issues we have:

(defstruct (v3 (:type (vector double-float)))
  (x 0d0)
  (y 0d0)
  (z 0d0))

Now we can MAKE-V3:
(make-v3) => #(0.0d0 0.0d0 0.0d0)

And find its type:
(type-of *) => (SIMPLE-ARRAY DOUBLE-FLOAT (3))

You may have missed the point if you need to use AREF on the simple array:
(make-v3 :z 1d0) => #(0.0d0 0.0d0 1.0d0)
(v3-z *) => 1.0d0

The DEFSTRUCT notation (it was new to me) appears to be an optimised
version of this code:

(defun make-v3 (&key (x 0d0) (y 0d0) (z 0d0))
  (make-array 3 :element-type 'double-float
                :initial-contents (vector x y z)))

(declaim (inline v3-x))
(defun v3-x (simple-array)
  (aref (the (simple-array double-float) simple-array) 0))

(declaim (inline v3-y))
(defun v3-y (simple-array)
  (aref (the (simple-array double-float) simple-array) 1))

(declaim (inline v3-z))
(defun v3-z (simple-array)
  (aref (the (simple-array double-float) simple-array) 2))

Regards,
Adam
From: Jeff M.
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <1102694104.909498.223290@z14g2000cwz.googlegroups.com>
Thanks for the reply. As I started looking at the hyperspec closer, I
was beginning to get some of what you are saying. It turns out to not
be that big a deal, though. I just used the list type. And surprisingly
enough, it is actually faster (by quite a bit) on the benchmarks, and
quite easier to use (the double-float problems go away).

Jeff M.
From: Wade Humeniuk
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <SNkud.17037$U47.14228@clgrps12>
Jeff M. wrote:

> Thanks for the reply. As I started looking at the hyperspec closer, I
> was beginning to get some of what you are saying. It turns out to not
> be that big a deal, though. I just used the list type. And surprisingly
> enough, it is actually faster (by quite a bit) on the benchmarks, and
> quite easier to use (the double-float problems go away).

You mean like?

(defun v3-lcross (v1 v2)
   "Returns the cross product of two, 3D vectors."
   (declare (optimize (speed 3) (float 0) (safety 0)))
   (destructuring-bind (v10 v11 v12) v1
     (declare (type double-float v10 v11 v12))
     (destructuring-bind (v20 v21 v22) v2
       (declare (type double-float v20 v21 v22))
       (list (- (* v11 v22) (* v12 v21))
             (- (* v12 v20) (* v10 v22))
             (- (* v10 v21) (* v11 v20))))))

Yes, it seems to much faster.

(defun v3-lcross-test ()
   (let ((v1 (list 3.0 1.23 4.5))
         (v2 (list 4.5 19.43 3.1)))
     (dotimes (i 1000000)
       (v3-lcross v1 v2))))

CL-USER 19 > (time (v3-lcross-test))
Timing the evaluation of (V3-LCROSS-TEST)
; Loading fasl file C:\Program Files\Xanalys\LispWorks\lib\4-3-0-0\modules\util\callcoun.fsl

user time    =      1.301
system time  =      0.000
Elapsed time =   0:00:01
Allocation   = 48002552 bytes standard / 33004092 bytes conses
0 Page faults
Calls to %EVAL    33
NIL

I seen this behaviour where using lists is faster than arrays.
My theory is that LW allocates short lists much faster than arrays.
If you disassemble v3-lcross it is also interesting to see that there
is a specialized LW function that creates lists of three elements.
system::list-3arg

Wade
From: Pascal Bourguignon
Subject: Re: Re Profiling Lisp code
Date: 
Message-ID: <87brd2t57k.fsf@thalassa.informatimago.com>
Wade Humeniuk <····································@telus.net> writes:
> I seen this behaviour where using lists is faster than arrays.
> My theory is that LW allocates short lists much faster than arrays.
> If you disassemble v3-lcross it is also interesting to see that there
> is a specialized LW function that creates lists of three elements.
> system::list-3arg

It's a case where you trade space for speed. For sequential access,
it's faster to dereference a cdr pointer than to index an array.
It's the same kind of optimization as using *a++ in C instead of a[i++].

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
The world will now reboot; don't bother saving your artefacts.