[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Optimizing record accessors
From: |
Ludovic Courtès |
Subject: |
Optimizing record accessors |
Date: |
Tue, 07 Aug 2007 17:00:06 +0200 |
User-agent: |
Gnus/5.11 (Gnus v5.11) Emacs/22.1 (gnu/linux) |
Hi,
Currently, accessing a record is slow. Consider this sample:
===File ~/src/guile-core/,,record-prof.scm==================
(use-modules (statprof)
(srfi srfi-9))
(define-record-type <stuff>
(make-stuff x y z)
stuff?
(x stuff-x)
(y stuff-y)
(z stuff-z))
(define stuff (make-stuff 1 2 3))
(with-statprof #:hz 20 #:loop 1000000
(stuff-x stuff))
============================================================
(SRFI-9 uses the record layer.)
Here is what we observe:
$ ./pre-inst-guile ,,record-prof.scm
% cumulative self
time seconds seconds name
33.33 2.95 0.98 #{statprof\ 0}#
27.45 0.81 0.81 record-type-descriptor
17.65 1.91 0.52 stuff-x
15.69 1.39 0.46 %record-type-check
3.92 0.93 0.12 eq?
1.96 0.06 0.06 not
---
Sample count: 51
Total time: 2.95 seconds (9/25 seconds in GC)
Changing `record-accessor' as in the attached file yields this:
$ ./pre-inst-guile ,,record-prof.scm
% cumulative self
time seconds seconds name
46.88 1.89 0.89 #{statprof\ 0}#
43.75 0.95 0.83 stuff-x
6.25 0.12 0.12 eq?
3.13 0.06 0.06 not
---
Sample count: 32
Total time: 1.89 seconds (1/5 seconds in GC)
A 36% improvement.
Type-safety is still guaranteed (e.g., `struct-vtable' will fail if OBJ
is not a struct), though not as precisely (e.g., instead of a
`not-a-record' error, we get a `wrong-type-arg' error in
`struct-vtable'). Thus, for instance, `srfi-9.test' will have to be
relaxed as to the exception type expected (which is reasonable anyway
since SRFI-9 does not specify error types).
I believe the improvement is worth the change, otherwise people may end
up using vectors or their own record abstraction.
Ok to commit?
Thanks,
Ludovic.
--- orig/ice-9/boot-9.scm
+++ mod/ice-9/boot-9.scm
@@ -429,7 +429,7 @@
(define (record-predicate rtd)
(lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj)))))
-(define (%record-type-check rtd obj) ;; private helper
+(define (%record-type-error rtd obj) ;; private helper
(or (eq? rtd (record-type-descriptor obj))
(scm-error 'wrong-type-arg "%record-type-check"
"Wrong type record (want `~S'): ~S"
@@ -441,8 +441,9 @@
(if (not pos)
(error 'no-such-field field-name))
(local-eval `(lambda (obj)
- (%record-type-check ',rtd obj)
- (struct-ref obj ,pos))
+ (if (eq? (struct-vtable obj) ,rtd)
+ (struct-ref obj ,pos)
+ (%record-type-error ,rtd obj)))
the-root-environment)))
(define (record-modifier rtd field-name)
@@ -450,7 +451,8 @@
(if (not pos)
(error 'no-such-field field-name))
(local-eval `(lambda (obj val)
- (%record-type-check ',rtd obj)
- (struct-set! obj ,pos val))
+ (if (eq? (struct-vtable obj) ,rtd)
+ (struct-set! obj ,pos val)
+ (%record-type-error ,rtd obj)))
the-root-environment)))
- Optimizing record accessors,
Ludovic Courtès <=