(archive 'newLISPer)

May 14, 2006

Time flies

Filed under: newLISP — newlisper @ 18:19
Tags:

Recently I’ve been unable to find the time to write anything worth reading, unfortunately. But I had a few minutes to spare today, so as I was going through some accumulated detritus I found a bit of newLISP that I’d made a note of some months ago and hadn’t got round to understanding. It was contributed by newLISP guru Fanda on the forum, and it was a small demonstration of how newLISP can look in the mirror at itself, which I found pleasing.

Here’s the code:

(define (time-expr _expressions _N)
  (if (not (apply = (map eval _expressions)))
   (begin
    (map (lambda (_e) (println _e " => " (eval _e))) _expressions)
    (throw-error "Return values of timed expressions do not match!")))
  (set 'timings (map (lambda (_e) (time (eval _e) _N)) _expressions))
  (set 'lentimes (apply max (map (lambda (x) (length (string x))) timings)))
  (set 'mx (apply max timings))

  (if (= _maxtime 0)
   (println "All times are 0!")
   (map (lambda (t _e)
 (println
  (format (append "%" (string lentimes) "d") t) " ms : "
  (format "%5.1f" (mul (div t mx) 100)) "% | " _e))
    timings _expressions)))

This function takes a list of expressions and a number. If the expressions are equivalent (ie if they return the same thing), newLISP runs them and times them (time (eval _e) N) and then displays the results.

Here’s how you would run it:

(set 'lst (sequence 1 1000))
; double each element of a list
(time-expr
 '((map (lambda (x) (* 2 x)) lst)
   (map * (dup 2 (length lst)) lst)
   (map mul (dup 2 (length lst)) lst)
   (map + lst lst)
   (map add lst lst)
   (begin (set 'r '()) (dolist (x lst) (push (+ x x) r -1)) r))
        1000)

and this is what you’d see:

2010 ms : 100.0% | (map (lambda (x) (* 2 x)) lst)
1050 ms :  52.2% | (map * (dup 2 (length lst)) lst)
 990 ms :  49.3% | (map mul (dup 2 (length lst)) lst)
 926 ms :  46.1% | (map + lst lst)
 862 ms :  42.9% | (map add lst lst)
 941 ms :  46.8% | (begin
                               (set 'r '())
                               (dolist (x lst)
                                 (push (+ x x) r -1)) r)

(I’ve cheated a bit – the last one doesn’t format itself as nicely.)

If milliseconds were important to you, this might offer you some clues as to how you could wax your newLISP skis, oil your newLISP chains, and tighten your newLISP bolts. I just think it’s neat.

And I’ve haven’t yet decided whether you can draw profound conclusions from this short example (apart from the fact that my computer isn’t very quick). Any suggestions?

Advertisements

5 Comments »

  1. >Hi cor…newlisper :-)> Recently I’ve been unable to find the time to write anything worth reading:-( > But I had a few minutes to spare today :-) > a small demonstration of how newLISP can look in the mirror at itself This self-reflection is something I always miss when I’m in languages that prevent this sort of thing. Statically typed languages are the ones most guilty of this. No problem in our neck of the woods, though. I’m really beginning to appreciate newLISP’s transparency. > If milliseconds were important to you Isn’t perceived speed actually more important to us than actual speed? I’m thinking about experminents comparing subjects’ perceptions of how long certain actions would take against measured time. The findings were interesting and revealed that we are bad judges of how long things actually take to do. We perceive some short periods of time as longer, some times as much as double or triple the actual time taken, and some longer spans of time as much shorter. Context played a large part, as well as sequence. Also, the lengths of time that were under examination were short (seconds), so this makes it particularly relevant to programmers. Now that I think about it, maybe this study was measuring people’s responses to using GUIs. I wish I could remember were I read about this. (sigh) > And I’ve haven’t yet decided whether you can draw profound conclusions from this short example (apart from the fact that my computer isn’t very quick). Any suggestions? No practical suggestions here, but I always seem to have aesthetic observations :-) Which do you prefer? (begin (set ‘r ‘()) (dolist (x lst) (push (+ x x) r -1)) r) or (let (r ‘()) (dolist (x lst) (push (+ x x) r -1)) r)The second is only six characters shorter, but in some ways, the first one is a pattern for what the second one is an abstraction of. The first argument to let implies the set. One difference I just thought of is . . . well, let me just test it here. > (set ‘x 99) 99 > (begin (set ‘x 88) (+ x x)) 176 > x 88 > ; yes, x was changed from within begin > (let (x 99) (+ x x)) 198 > x 88 > ; no, the x in let is local My hunch was right. let’s symbols are local, while begin’s are not. I did time each, and as far as I could tell, the difference was negligible. Turned out to be more than looks, after all :-)One last thing before this becomes a novel. I noticed that Fanda prepended underscores to his argument and local symbols. Is this how newLISPers commonly distinguish between top-level and local symbols? This idiom would certainly make it possible to filter those out if needed. Lutz mentioned somewhere that the underscores were unnecessary (in the context of macros, I think), and I wonder now what he meant. Do you know?m i c h a e l

    Comment by m i c h a e l — May 15, 2006 @ 15:14 | Reply

  2. >Yes, timing stuff is important when tuning for maximum performance. I always use ‘time’ with the extra repetition parameter, like in:> (time (set ‘x 123) 1000000)292> If you do a million repetitions as in the example the result is in nano seconds (1000 nano sec = 1 micro sec). Most newLISP functions are in that area of duration on a Mac Mini. Underscores are not really necessary, its just a convention when using ‘define-macro’ to make avoiding variable capture easier.But what I do more and more is not use parameter vars in define-macro at all but use (args), i.e:Instead of:(define-macro (my-setq _x _y) (set _x (eval _y))) I use:(define-macro (my-setq) (set (args 0) (eval (args 1))))(my-setq x 123) => 123x => 123now the function is 100% safe for variable capture.In a multiprogrammer environment I always recommend putting code in context modules, this way giving them a lexical closure.Lutz

    Comment by don Lucio — May 15, 2006 @ 21:57 | Reply

  3. >Lutz said: But what I do more and more is not use parameter vars in define-macro at all but use (args)Noticed I’ve been using (args) in almost all of my regular functions, as well. Very helpful if you decide later to have multiple arguments, like in set or constant.m i c h a e l

    Comment by m i c h a e l — May 18, 2006 @ 01:16 | Reply

  4. >Oops, here’s a slop report on the function ‘time-expr’.The following variables are not local: ‘timings’, ‘lentimes’ and ‘mx’. This means that you could trounce the values of higher level variables with the same name. I recommend scoping them locally with a ‘let’.Also, ‘_maxtime’ is never assigned a value — it looks as if ‘mx’ should be substituted for ‘_maxtime’.What do you think? Cheers, –rickyboy

    Comment by Rick Hanson — May 20, 2006 @ 12:27 | Reply

  5. >Hey Ricky – thanks again. Your expert eye will always find ways to improve my first attempt. The mistake was mine, not Fanda’s, and the use of non-local variables was probably because it was just a throwaway function designed to explain to me the cost of mapping lambda functions, rather than a serious bit of production code. But you’re right in that these habits are important to get into!

    Comment by newlisper — May 20, 2006 @ 18:44 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: