-
-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Revise for better performance. #34
base: master
Are you sure you want to change the base?
Conversation
#18 is linked to this PR, as if it fixes the issue. But if I understand correctly, the issue is not fixed, right? |
Ah, I thought I had fixed that but now I did for real. |
* Eliminates contracts in favor of inline checks. * Specializes multiple-value code to improve single-value performance (see racket/racket#4942). * Use simpler non-recursive growth computation (taken from Rust's Vector implementation). * Avoid duplicate work in core operations. * Add #:capacity arguments. * Use unsafe operations. * Use `vector-extend` from racket/racket#4943.
Performance compared to mut-treelist before:
After:
|
This is ready to merge, right? |
From my perspective yes although I was hoping for a review from @rmculpepper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gvectors were previously unsynchronized and so not thread-safe. The introduction of unsafe operations makes them potentially memory-unsafe, and we need to make sure gvector operations, even used concurrently, are still memory-safe.
The gv-ensure-space!
pattern helps: it means that writes to the vector have enough space, whether or not that vector is actually installed as the gvector's vec
field at the end of the operation (eg, because of two racing add
operations). I'm worried about the write to n
afterwards; in a race, it might point past the end of vec
.
I've pointed out a problem in gvector-ref
if there is a concurrent call that shrinks the gvector. It also occurs if n
is greater than the length of the vector. Other read operations (iteration, for example) might have similar problems, but I haven't checked them all.
If unsafe operations are used, we need to figure out and document invariants and patterns of field updates that actually preserve memory-safety.
(define v (ensure-free-space-vec! (gvector-vec gv) (gvector-n gv) needed-free-space)) | ||
(when v (set-gvector-vec! gv v))) | ||
|
||
(define-syntax-rule (gv-ensure-space! gv n v needed-free-space) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a syntax like (define/ensure-space! (n v) gv needed-free-space)
would better signal what this macro is doing.
(unless (exact-nonnegative-integer? index) | ||
(raise-type-error 'gvector-ref "exact nonnegative integer" index)) | ||
(if (< index (gvector-n gv)) | ||
(vector-ref (gvector-vec gv) index) | ||
(unsafe-vector*-ref (gvector-vec gv) index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unsafe if a concurrent call to remove shrinks the vector. That is, if (gvector-n gv)
in the previous line is fetched before the call to remove and (gvector-vec gv)
is fetched afterwards, the n
might be stale and the vector can be too short.
(cond [(eq? default none) | ||
(check-index 'gvector-ref gv index #f)] | ||
[(procedure? default) (default)] | ||
[else default]))) | ||
|
||
;; gvector-set! with index = |gv| is interpreted as gvector-add! | ||
(define (gvector-set! gv index item) | ||
(check-gvector 'gvector-set gv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be 'gvector-set!
(gvector-add! gv item) | ||
(vector-set! (gvector-vec gv) index item)))) | ||
(if (unsafe-fx= index n) | ||
(unsafe-gvector-add! gv item) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why unsafe-gvector-add!
's precondition (not a chaperone) is satisfied here.
single-value performance (see Optimizations and benchmarks for gvectors racket#4942).
(taken from Rust's Vector implementation).
vector-extend
from Addvector-extend
. racket#4943.