io: add shortcut to get semaphore on blocking fd read

When reading from an input fd blocks, instead of creating a general
event that creates a semaphore, use the semaphore directly (when
available). Also, treat a semaphore internally as an event that
always produces 0.

This change speeds up the "echo" shootout benchmark.

This change speeds up the "echo" shootout benchmark.
This commit is contained in:
Matthew Flatt 2019-06-17 09:40:18 -06:00
parent 97e61b5f25
commit 1824fe5e41
3 changed files with 33 additions and 6 deletions

View File

@ -61,8 +61,8 @@
(end-atomic)
(send fd-input-port this raise-read-error n)]
[(eqv? n RKTIO_READ_EOF) eof]
[(eqv? n 0) (wrap-evt (fd-evt fd RKTIO_POLL_READ this)
(lambda (v) 0))]
[(eqv? n 0) (or (fd-semaphore-update! fd 'read)
(fd-evt fd RKTIO_POLL_READ this))]
[else n]))]
[close
@ -379,6 +379,9 @@
;; ----------------------------------------
;; The ready value for an `fd-evt` is 0, so it can be used directly
;; for an input port
(struct fd-evt (fd mode [closed #:mutable])
#:property
prop:evt
@ -388,7 +391,7 @@
(lambda (fde ctx)
(cond
[(core-port-closed? (fd-evt-closed fde))
(values (list fde) #f)]
(values '(0) #f)]
[else
(define mode (fd-evt-mode fde))
(define ready?
@ -401,7 +404,7 @@
RKTIO_POLL_READY))))
(cond
[ready?
(values (list fde) #f)]
(values '(0) #f)]
;; If the called is going to block (i.e., not just polling), then
;; try to get a semaphore to represent the file descriptor, because
;; that can be more scalable (especially for lots of TCP sockets)
@ -411,7 +414,7 @@
'read
'write)))
=> (lambda (s) ; got a semaphore
(values #f (wrap-evt s (lambda (s) fde))))]
(values #f (wrap-evt s (lambda (s) 0))))]
[else
;; If `sched-info` in `poll-ctx` is not #f, then we can register this file
;; descriptor so that if no thread is able to make progress,

View File

@ -74,7 +74,8 @@
;; be exposed to untrusted code, and instead of should be copied if
;; necessary. The return values are the same as documented for
;; `make-input-port`, except that a pipe result is not allowed (or,
;; more precisely, it's treated as an event).
;; more precisely, it's treated as an event), and a semaphore is
;; treated like an event that produces 0.
[read-in (lambda (bstr start end copy?) eof)]
;; port or (bytes start-k end-k skip-k progress-evt copy? -*> (or/c integer? ...))

View File

@ -101,6 +101,21 @@
"result" v
"byte-string length" (- end start))])]
[(eof-object? v) eof]
[(semaphore? v)
;; A semaphore is treated as a special case, making
;; it equivalent to an evt that returns 0
(cond
[zero-ok?
;; Poll:
(cond
[(semaphore-try-wait? v)
(loop in extra-count-ins)]
[else 0])]
[else
(if enable-break?
(semaphore-wait/enable-break v)
(semaphore-wait v))
(loop in extra-count-ins)])]
[(evt? v)
;; If `zero-ok?`, we should at least poll the event
(define timeout (if zero-ok? (lambda () 0) #f))
@ -186,6 +201,14 @@
"result" v
"byte-string length" (- end start))])]
[(eof-object? v) eof]
[(semaphore? v)
(cond
[zero-ok? 0]
[else
(if enable-break?
(semaphore-wait/enable-break v)
(semaphore-wait v))
(loop in)])]
[(evt? v)
(cond
[zero-ok? 0]