Newbie: How to avoid allocation of locals ?

Discussion of Common Lisp
Post Reply
ksubox
Posts: 1
Joined: Sun Feb 21, 2010 6:58 pm

Newbie: How to avoid allocation of locals ?

Post by ksubox » Sun Feb 21, 2010 7:14 pm

Hi,
I made test function to check behavior of Lisp for locals:

(defun strinc (str cnt)
(let ((lstr str))
(declare (integer cnt) (simple-base-string str) (simple-base-string lstr)
(optimize (speed 3) (safety 3) (debug 3) (compilation-speed 0) (space 0)))
(dotimes (i cnt)
(setf lstr (prin1-to-string (1+ (parse-integer lstr)))))
lstr))

Then I tested in OpenMCL:
? (time (strinc "1" 1000))
(STRINC "1" 1000) took 16 milliseconds (0.016 seconds) to run with 4 available CPU cores.
During that period, 15 milliseconds (0.015 seconds) were spent in user mode
0 milliseconds (0.000 seconds) were spent in system mode
40,136 bytes of memory allocated.
"1001"
? (time (strinc "1" 10000))
(STRINC "1" 10000) took 31 milliseconds (0.031 seconds) to run with 4 available CPU cores.
During that period, 32 milliseconds (0.032 seconds) were spent in user mode
0 milliseconds (0.000 seconds) were spent in system mode
472,208 bytes of memory allocated.
"10001"

I see, Lisp allocate a lot of memory for temporary variables. LispWorks & Allegro do the same.

Does any method exist to avoid reallocation ? Or any programming technics to minimize temporal allocations in Lisp ?

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Newbie: How to avoid allocation of locals ?

Post by ramarren » Sun Feb 21, 2010 11:53 pm

Code: Select all

(declare (integer cnt) (simple-base-string str) (simple-base-string lstr)
             (optimize (speed 3) (safety 3) (debug 3) (compilation-speed 0) (space 0)))
You have declared 'cnt' to be 'integer', which does mostly nothing from optimization perspective. Integers in Common Lisp are arbitrary sized integers and can be boxed. You declared maximum debug and safety, which disallows omitting any type checks or allocations. And this doesn't even run on my SBCL, since the strings are not 'simple-base' when unicode is enabled. You have declared (space 0), which means you don't care about memory use. The basic technique to avoid allocation would be not to ask for it.

Not that in this particular case it matters since there aren't any locals anyway, all allocation is internal to the printer/parser, or flow of data between them. Even declaring lstr to be DYNAMIC-EXTENT does nothing, since you cannot stack allocate variable length string.

Anyway, in most cases this doesn't matter, relatively modern garbage collectors, which is what most modern Lisps have, deal well with small short-lived garbage. This is not really a matter to worry about unless you have identified it as your bottleneck.

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: Newbie: How to avoid allocation of locals ?

Post by gugamilare » Mon Feb 22, 2010 7:21 am

ksubox wrote:Hi,
I made test function to check behavior of Lisp for locals:

Code: Select all

(defun strinc (str cnt)
  (let ((lstr str))
    (declare (integer cnt) (simple-base-string str) (simple-base-string lstr)
      (optimize (speed 3) (safety 3) (debug 3) (compilation-speed 0) (space 0)))
    (dotimes (i cnt)
      (setf lstr (prin1-to-string (1+ (parse-integer lstr)))))
    lstr))
[...]

I see, Lisp allocate a lot of memory for temporary variables. LispWorks & Allegro do the same.

Does any method exist to avoid reallocation ? Or any programming technics to minimize temporal allocations in Lisp ?
In this case, the lots of bytes consed is because you are creating one new string to every increment you do. If this is what you want to do, there is only a few things you can do about it. In your tests, there is about 40 bytes consed to each iteration, which I already consider a very reasonable amount.

To avoid consing, the best thing you can do is to change the declaration (integer cnt) to (fixnum cnt). You could remove the (space 0) declaration, as Ramarren already implied, or change it to (space 3), but that probably will not save run time for your function, only space. Another thing that might give you some result is to remove (debug 3) and (safety 3) or change them to (debug 0) and (safety 0). Turning off safety usually have a big impact on speed, but also might be dangerous if you don't call the function with the correct arguments, so this is your choice.

Note that putting the declaration (space 0) in this function is a bit extreme, specially for this function which already allocates some bytes by its nature.

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

Re: Newbie: How to avoid allocation of locals ?

Post by nuntius » Mon Feb 22, 2010 12:10 pm

FWIW, there are very few places where (safety 0) is a win over (safety 1).

Post Reply