From: Madhu on

* Robert Uhl <m3iqaz8n3l.fsf(a)latakia.octopodial-chrome.com> :
Wrote on Mon, 18 Jan 2010 08:11:10 -0700:

| "Frode V. Fjeld" <frode(a)netfonds.no> writes:
|>
|> I.e. to hash over some combination of each key's sxhash (taking care
|> not to combine them so as to generate a bignum).
|
| Note that SXHASH doesn't care about anything more than the top level
| of a list:
|
| cl-user> (sxhash '(1 2 3 (4)))
| 224526978
| cl-user> (sxhash '(1 2 3 (4 5)))
| 224526978

I believe Frodef was suggesting you should do something like:

* (reduce 'logior '(1 2 3 (4)) :key #'sxhash)
1031

* (reduce 'logior '(1 2 3 (4 5)) :key #'sxhash)
526343

--
Madhu
From: Pillsy on
On Jan 18, 3:14 am, Tamas K Papp <tkp...(a)gmail.com> wrote:
> On Sun, 17 Jan 2010 23:37:26 +0200, Captain Obvious wrote:
[...]
> > Now my version is faster by whopping 7%!

> Nope.  If you do a shitload of lookups, you just inline the bloody
> thing.

This is good advice, but if inlining isn't an option for some reason,
you have another route which also involves just a single declaration
and eliminates consing: the DYNAMIC-EXTENT declaration.

I tried three versions of the hash lookup, without inlining, on SBCL
1.0.21 (gee, maybe it's time to upgrade?)

;;; lookup-test.lisp
(declaim (optimize speed))

(defun simple-lookup (ht k1 k2)
(gethash (cons k1 k2) ht))

(progn
(let ((the-cons (cons nil nil)))
(defun ugly-lookup (ht k1 k2)
(setf (car the-cons) k1
(cdr the-cons) k2)
(gethash the-cons ht))))

(defun dx-lookup (ht k1 k2)
(let ((the-cons (cons k1 k2)))
(declare (dynamic-extent the-cons))
(gethash the-cons ht)))

(progn
(defparameter *ht* (make-hash-table :test #'equal))
(setf (gethash (cons 5 10) *ht*) 10))

(defmacro deftest (name fn)
`(defun ,name ()
(time (dotimes (i 10000000)
(,fn *ht* 5 10)))))

(deftest test-simple-lookup simple-lookup)
(deftest test-ugly-lookup ugly-lookup)
(deftest test-dx-lookup dx-lookup)

; compiling file "/Users/mtp/lisp/lookup-test.lisp" (written 18 JAN
2010 11:40:01 AM):

; /Users/mtp/lisp/lookup-test.fasl written
; compilation finished in 0:00:00
NIL
CL-USER> (test-simple-lookup)
Evaluation took:
1.813 seconds of real time
1.799895 seconds of total run time (1.784424 user, 0.015471 system)
[ Run times consist of 0.031 seconds GC time, and 1.769 seconds non-
GC time. ]
99.28% CPU
3,917,843,462 processor cycles
79,998,984 bytes consed
NIL

CL-USER> (test-ugly-lookup)
Evaluation took:
3.432 seconds of real time
3.407829 seconds of total run time (3.396038 user, 0.011791 system)
99.30% CPU
7,418,751,288 processor cycles
5,008 bytes consed
NIL

CL-USER> (test-dx-lookup)
Evaluation took:
1.755 seconds of real time
1.745271 seconds of total run time (1.736452 user, 0.008819 system)
99.43% CPU
3,794,412,856 processor cycles
0 bytes consed

DX-LOOKUP is a tiny bit faster than SIMPLE-LOOKUP, and does no
consing, just like UGLY-LOOKUP, all by adding a single declaration
that expresses its intent very clearly.

Cheers,
Pillsy
From: Frode V. Fjeld on
Madhu <enometh(a)meer.net> writes:

> I believe Frodef was suggesting you should do something like:
>
> * (reduce 'logior '(1 2 3 (4)) :key #'sxhash)
> 1031

Actually this is precisely what I wrote originally before I substituted
(sxhash keys). But like I said there are several considerations to make
here, most of which are dependant on the application's requirements and
the (performance) characteristics of the lisp implementation.

--
Frode V. Fjeld
From: Tamas K Papp on
On Mon, 18 Jan 2010 08:46:57 -0800, Pillsy wrote:

> On Jan 18, 3:14 am, Tamas K Papp <tkp...(a)gmail.com> wrote:
>> On Sun, 17 Jan 2010 23:37:26 +0200, Captain Obvious wrote:
> [...]
>> > Now my version is faster by whopping 7%!
>
>> Nope.  If you do a shitload of lookups, you just inline the bloody
>> thing.
>
> This is good advice, but if inlining isn't an option for some reason,
> you have another route which also involves just a single declaration and
> eliminates consing: the DYNAMIC-EXTENT declaration.
>
> I tried three versions of the hash lookup, without inlining, on SBCL
> 1.0.21 (gee, maybe it's time to upgrade?)

Probably :-)

> DX-LOOKUP is a tiny bit faster than SIMPLE-LOOKUP, and does no consing,
> just like UGLY-LOOKUP, all by adding a single declaration that expresses
> its intent very clearly.

I rarely (if ever) use dynamic extend declarations in SBCL, it is
usually pretty good at figuring out stuff. Well, maybe not always,
but generally it is not worth even thinking about these things.

Anyhow, I think that we have pretty much beaten this example to death.
Also, AFAIK in SBCL gethash caches the last key, so we are testing the
cost of an equality comparison. In real life the cost of finding a
different key each time in the table would most likely dominate.

Tamas
From: Robert Uhl on
Madhu <enometh(a)meer.net> writes:
> |
> | Note that SXHASH doesn't care about anything more than the top level
> | of a list:
> |
> | cl-user> (sxhash '(1 2 3 (4)))
> | 224526978
> | cl-user> (sxhash '(1 2 3 (4 5)))
> | 224526978
>
> I believe Frodef was suggesting you should do something like:
>
> * (reduce 'logior '(1 2 3 (4)) :key #'sxhash)
> 1031
>
> * (reduce 'logior '(1 2 3 (4 5)) :key #'sxhash)
> 526343

And yet:

cl-user> (reduce 'logior '(1 2 3 (4 5 6 (6 7))) :key #'sxhash)
501984895
cl-user> (reduce 'logior '(1 2 3 (4 5 6 (6 7 8))) :key #'sxhash)
501984895

The basic issue is that SXHASH really isn't the right tool for the
job--the guarantees that the standard gives aren't good enough for
generating a unique key, which is what's needed to key a hashtable.

That makes sense, since SXHASH is meant to _hash_ a unique key, and
collisions are expected.

--
Robert A. Uhl
Wilner's Observation:
All conversations with a potato should be conducted in private.
First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6
Prev: SBCL optimization
Next: what do lispers think of bigtable?