defining a variable inside a Defun

Discussion of Common Lisp
Post Reply
joeish80829
Posts: 153
Joined: Tue Sep 03, 2013 5:32 am

defining a variable inside a Defun

Post by joeish80829 » Sun Mar 30, 2014 12:23 am

I'm trying to show the result I'm after by showing the what I don't want. Here is the code I'm referring to, the way the functions work don't matter...I highlight how long it takes to run, them and that is what matters. Just keep an out because 2 functions in my question have names that are exactly the same except for a % at the front of it's name.


Code: Select all

(let ((val nil))
  (defun c-arr-to-vector-float  (a len)
    (cond (val val)
          ((listp a) (progn (setf val (foreign-alloc :float :initial-contents a)) 
			    (%c-arr-to-vector-float val len)))
	  (t nil))))

If I run this:

Code: Select all

 (%c-arr-to-vector-float (foreign-alloc :float :initial-contents '(1 2 3)) 3 )
1 million times, it takes 6 seconds. but if define

Code: Select all

(foreign-alloc :float :initial-contents (1 2 3)) 
first like:

Code: Select all

(defparameter a (foreign-alloc :float :initial-contents '(1 2 3)))
then run

Code: Select all

(%c-arr-to-vector-float a len) 
running

Code: Select all

(%c-arr-to-vector-float a len) 
only takes .017 seconds...do you see where I'm coming from here...I'm looking to speed up the above function? but each time I run the

Code: Select all

c-arr-to-vector-float function
with the let statement above I have to be able to put in a new value, i.e. every time this is run

Code: Select all

(c-arr-to-vector-float '(1 2 3) 3) 
(that's name of the defun in the let) the function should operate on the '(123) and if I give it a '(4 5 6) it should operate on that. And I don't want to make someone run the defparameter first each time, I'm trying to make it be automatic and everything inside one s-expression.

nuntius
Posts: 538
Joined: Sat Aug 09, 2008 10:44 am
Location: Newton, MA

Re: defining a variable inside a Defun

Post by nuntius » Sun Mar 30, 2014 9:30 am

It sounds like you are measuring the time to allocate, initialize, and free the "val" parameter a million times.

Is the following what you are looking for?

Code: Select all

(defun test ()
  (let ((arr (foreign-alloc :float :initial-contents '(1 2 3))))
    (dotimes (i 1000000)
      (%c-arr-to-vector-float arr 3))))

edgar-rft
Posts: 226
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: defining a variable inside a Defun

Post by edgar-rft » Sun Mar 30, 2014 3:46 pm

If I have understood your examples correctly then you want to avoid multiple evaluation of foreign-alloc by caching the old value in a lexical variable.

Code: Select all

(let (old-a val)
  (defun c-arr-to-vector-float (a len)
    (cond ((equal a old-a)  ; a is the same list as in the last call
           (%c-arr-to-vector-float val len))
          ((listp a)   ; a is a list but not the same as in the last call
           (setf old-a a
                 val (foreign-alloc :float :initial-contents a))
           (%c-arr-to-vector-float val len)))
          (t nil))))
The list from a is stored in old-a and the return-value of foreign-alloc is stored in val. If the function is called with a list that is not the same list as the list stored in old-a, then the list from a is stored in old-a, the return-value of foreign-alloc is computed and stored in val. If the function is called with a list that is the same list as the list stored in old-a, the old foreign-alloc return-value from val is used instead.

Caching computed values in a hash-table:

Code: Select all

;; EQUAL is needed here because the key is a list
(defvar hash-table (make-hash-table :test #'equal))

(defun c-arr-to-vector-float (a len)
  (let ((val (gethash a hash-table)))     ; try to get val from hash-table
    (cond (val (%c-arr-to-vector-float val len)) ; use val from hash-table
          ((listp a)
           (setf val (foreign-alloc :float :initial-contents a)
                 (gethash a hash-table) val)     ; store val in hash-table
           (%c-arr-to-vector-float val len))
          (t nil))))
All return-values of foreign-alloc are stored in the hash-table with the list from a as the respective key. If the function is called with a list who's value is not stored in the hash-table the value is computed once and stored in the hash-table. If the function is called with a list who's value is already stored in the hash-table, the value from the hash-table is used instead.

Special care must be taken that the hash-table doesn't grow bigger than the available memory.

- edgar

Post Reply