cs: further reduce allocation during thread swapping

This commit is contained in:
Matthew Flatt 2019-10-04 15:51:35 -06:00
parent f9e12dc9bc
commit d3d0bffb88
10 changed files with 86 additions and 74 deletions

View File

@ -53,7 +53,6 @@
engine-timeout engine-timeout
engine-return engine-return
call-with-engine-completion call-with-engine-completion
current-engine-state
set-ctl-c-handler! set-ctl-c-handler!
get-ctl-c-handler get-ctl-c-handler
set-scheduler-lock-callbacks! set-scheduler-lock-callbacks!

View File

@ -337,7 +337,7 @@
(#%apply values r)))])))))])))) (#%apply values r)))])))))]))))
;; Simplified `call-in-empty-metacontinuation-frame` suitable for swapping engines: ;; Simplified `call-in-empty-metacontinuation-frame` suitable for swapping engines:
(define (call-in-empty-metacontinuation-frame-for-swap proc) (define (call-with-empty-metacontinuation-frame-for-swap proc)
(assert-in-uninterrupted) (assert-in-uninterrupted)
(assert-not-in-system-wind) (assert-not-in-system-wind)
(call/cc (call/cc
@ -355,7 +355,7 @@
(current-winders '()) (current-winders '())
(current-mark-splice empty-mark-frame) (current-mark-splice empty-mark-frame)
(current-metacontinuation (cons mf (current-metacontinuation))) (current-metacontinuation (cons mf (current-metacontinuation)))
(let ([r (proc)]) (let ([r (proc (current-metacontinuation))])
(let ([mf (car (current-metacontinuation))]) (let ([mf (car (current-metacontinuation))])
(pop-metacontinuation-frame) (pop-metacontinuation-frame)
((metacontinuation-frame-resume-k mf) r))))))) ((metacontinuation-frame-resume-k mf) r)))))))
@ -1423,8 +1423,8 @@
(maybe-future-barricade orig-tag) (maybe-future-barricade orig-tag)
(let ([tag (strip-impersonator orig-tag)]) (let ([tag (strip-impersonator orig-tag)])
(cond (cond
[(#%procedure? k) [(#%procedure? k) ; => an engine
(let ([mc (saved-metacontinuation-mc (k))]) (let ([mc (k)])
(make-continuation-mark-set (make-continuation-mark-set
(prune-mark-chain-suffix (prune-mark-chain-suffix
who who
@ -1900,9 +1900,7 @@
;; ---------------------------------------- ;; ----------------------------------------
;; Metacontinuation swapping for engines ;; Metacontinuation swapping for engines
(define-record saved-metacontinuation (mc system-winders exn-state)) (define empty-metacontinuation '())
(define empty-metacontinuation (make-saved-metacontinuation '() '() (create-exception-state)))
;; Similar to `call-with-current-continuation` plus ;; Similar to `call-with-current-continuation` plus
;; applying an old continuation, but does not run winders; ;; applying an old continuation, but does not run winders;
@ -1913,17 +1911,10 @@
[(current-system-wind-start-k) [(current-system-wind-start-k)
=> (lambda (k) (call-with-current-metacontinuation-with-system-wind proc k))] => (lambda (k) (call-with-current-metacontinuation-with-system-wind proc k))]
[else [else
(call-in-empty-metacontinuation-frame-for-swap (call-with-empty-metacontinuation-frame-for-swap proc)]))
(lambda ()
(proc (make-saved-metacontinuation
(current-metacontinuation)
(#%$current-winders)
(current-exception-state)))))]))
(define (apply-meta-continuation saved k) (define (apply-meta-continuation saved k)
(current-metacontinuation (saved-metacontinuation-mc saved)) (current-metacontinuation saved)
(#%$current-winders (saved-metacontinuation-system-winders saved))
(current-exception-state (saved-metacontinuation-exn-state saved))
(k)) (k))
;; ---------------------------------------- ;; ----------------------------------------

View File

@ -11,7 +11,7 @@
(define-record engine-state (complete-or-expire thread-cell-values init-break-enabled-cell)) (define-record engine-state (complete-or-expire thread-cell-values init-break-enabled-cell))
(define-virtual-register current-engine-state #f) (define-virtual-register current-engine-state (make-engine-state #f #f #f))
(define (set-ctl-c-handler! proc) (define (set-ctl-c-handler! proc)
(keyboard-interrupt-handler (case-lambda (keyboard-interrupt-handler (case-lambda
@ -26,6 +26,18 @@
(define (set-engine-exit-handler! proc) (define (set-engine-exit-handler! proc)
(set! engine-exit proc)) (set! engine-exit proc))
(define (currently-in-engine?)
(engine-state-complete-or-expire (current-engine-state)))
(define (set-current-engine-state! complete-or-expire thread-cell-values init-break-enabled-cell)
(let ([es (current-engine-state)])
(set-engine-state-complete-or-expire! es complete-or-expire)
(set-engine-state-thread-cell-values! es thread-cell-values)
(set-engine-state-init-break-enabled-cell! es init-break-enabled-cell)))
(define (clear-current-engine-state!)
(set-current-engine-state! #f #f #f))
;; An engine is repesented by a procedure that takes three arguments, where the ;; An engine is repesented by a procedure that takes three arguments, where the
;; procedure must be tail-called either within `call-with-engine-completion` or ;; procedure must be tail-called either within `call-with-engine-completion` or
;; in an engine call's `complete-or-expire` callback: ;; in an engine call's `complete-or-expire` callback:
@ -81,9 +93,7 @@
(apply-meta-continuation (apply-meta-continuation
to-saves to-saves
(lambda () (lambda ()
(current-engine-state (set-current-engine-state! complete-or-expire thread-cell-values init-break-enabled-cell)
(make-engine-state complete-or-expire thread-cell-values init-break-enabled-cell))
(reset-handler engine-reset-handler)
(timer-interrupt-handler engine-block-via-timer) (timer-interrupt-handler engine-block-via-timer)
(end-implicit-uninterrupted 'create) (end-implicit-uninterrupted 'create)
(set-timer ticks) (set-timer ticks)
@ -95,18 +105,25 @@
(define (call-with-engine-completion proc) (define (call-with-engine-completion proc)
(call-with-current-metacontinuation (call-with-current-metacontinuation
(lambda (saves) (lambda (saves)
(let ([rh (reset-handler)]) (let ([rh (reset-handler)]
[ws (#%$current-winders)]
[exns (current-exception-state)])
(reset-handler engine-reset-handler)
(#%$current-winders '())
(current-exception-state (create-exception-state))
(proc (lambda args (proc (lambda args
(current-engine-state #f) (clear-current-engine-state!)
(apply-meta-continuation (apply-meta-continuation
saves saves
(lambda () (lambda ()
(reset-handler rh) (reset-handler rh)
(#%$current-winders ws)
(current-exception-state exns)
(#%apply values args))))))))) (#%apply values args)))))))))
(define (engine-reset-handler) (define (engine-reset-handler)
(end-uninterrupted 'reset) (end-uninterrupted 'reset)
(if (current-engine-state) (if (currently-in-engine?)
(engine-return (void)) (engine-return (void))
(chez:exit))) (chez:exit)))
@ -122,25 +139,25 @@
[(timeout?) [(timeout?)
(assert-not-in-uninterrupted) (assert-not-in-uninterrupted)
(timer-interrupt-handler void) (timer-interrupt-handler void)
(let ([es (current-engine-state)] (let ([complete-or-expire (engine-state-complete-or-expire (current-engine-state))]
[thread-cell-values (engine-state-thread-cell-values (current-engine-state))]
[init-break-enabled-cell (engine-state-init-break-enabled-cell (current-engine-state))]
[remain-ticks (if timeout? [remain-ticks (if timeout?
0 0
(set-timer 0))]) (set-timer 0))])
(unless es (unless complete-or-expire
(error 'engine-block "not currently running an engine")) (error 'engine-block "not currently running an engine"))
(start-implicit-uninterrupted 'block) (start-implicit-uninterrupted 'block)
(call-with-current-metacontinuation (call-with-current-metacontinuation
(lambda (saves) (lambda (saves)
(end-implicit-uninterrupted 'block) (end-implicit-uninterrupted 'block)
(current-engine-state #f) (clear-current-engine-state!)
((engine-state-complete-or-expire es) (complete-or-expire (create-engine saves
(create-engine (lambda (prefix) (prefix))
saves thread-cell-values
(lambda (prefix) (prefix)) init-break-enabled-cell)
(engine-state-thread-cell-values es) #f
(engine-state-init-break-enabled-cell es)) remain-ticks))))]
#f
remain-ticks))))]
[() (engine-block #f)])) [() (engine-block #f)]))
(define (engine-block/timeout) (define (engine-block/timeout)
@ -160,16 +177,16 @@
(define (engine-return . results) (define (engine-return . results)
(assert-not-in-uninterrupted) (assert-not-in-uninterrupted)
(timer-interrupt-handler void) (timer-interrupt-handler void)
(let ([es (current-engine-state)]) (let ([complete-or-expire (engine-state-complete-or-expire (current-engine-state))])
(unless es (unless complete-or-expire
(error 'engine-return "not currently running an engine")) (error 'engine-return "not currently running an engine"))
(let ([remain-ticks (set-timer 0)]) (let ([remain-ticks (set-timer 0)])
(start-implicit-uninterrupted 'block) (start-implicit-uninterrupted 'block)
(call-with-current-metacontinuation (call-with-current-metacontinuation
(lambda (ignored-saves) (lambda (ignored-saves)
(end-implicit-uninterrupted 'block) (end-implicit-uninterrupted 'block)
(current-engine-state #f) (clear-current-engine-state!)
((engine-state-complete-or-expire es) #f results remain-ticks)))))) (complete-or-expire #f results remain-ticks))))))
(define (make-empty-thread-cell-values) (define (make-empty-thread-cell-values)
(make-ephemeron-eq-hashtable)) (make-ephemeron-eq-hashtable))
@ -179,10 +196,8 @@
(define original-thread-id (get-thread-id)) (define original-thread-id (get-thread-id))
(define (current-engine-thread-cell-values) (define (current-engine-thread-cell-values)
(let ([es (current-engine-state)]) (or (engine-state-thread-cell-values (current-engine-state))
(if es (root-thread-cell-values)))
(engine-state-thread-cell-values es)
(root-thread-cell-values))))
(define (set-current-engine-thread-cell-values! new-t) (define (set-current-engine-thread-cell-values! new-t)
(let ([current-t (current-engine-thread-cell-values)]) (let ([current-t (current-engine-thread-cell-values)])
@ -209,7 +224,5 @@
new-t)) new-t))
(define (current-engine-init-break-enabled-cell none-v) (define (current-engine-init-break-enabled-cell none-v)
(let ([es (current-engine-state)]) (or (engine-state-init-break-enabled-cell (current-engine-state))
(if es none-v))
(engine-state-init-break-enabled-cell es)
none-v)))

View File

@ -213,7 +213,7 @@
(define/who (ptr-equal? p1 p2) (define/who (ptr-equal? p1 p2)
(let ([p1 (unwrap-cpointer who p1)] (let ([p1 (unwrap-cpointer who p1)]
[p2 (unwrap-cpointer who p2)]) [p2 (unwrap-cpointer who p2)])
(with-interrupts-disabled ; disable GC while extracting addresses (with-interrupts-disabled* ; disable GC while extracting addresses
(= (cpointer-address p1) (cpointer-address p2))))) (= (cpointer-address p1) (cpointer-address p2)))))
(define/who (ptr-offset p) (define/who (ptr-offset p)
@ -900,7 +900,7 @@
(eq? 'utf-16be host-rep) (eq? 'utf-16be host-rep)
(eq? 'utf-32le host-rep) (eq? 'utf-32le host-rep)
(eq? 'utf-32be host-rep)) (eq? 'utf-32be host-rep))
(let ([v (with-interrupts-disabled (let ([v (with-interrupts-disabled*
(foreign-ref 'uptr (cpointer-address p) 0))]) (foreign-ref 'uptr (cpointer-address p) 0))])
(case host-rep (case host-rep
[(utf-16le) (utf16->string (uptr->bytes/2-byte-nul v) 'little #t)] [(utf-16le) (utf16->string (uptr->bytes/2-byte-nul v) 'little #t)]
@ -909,7 +909,7 @@
[(utf-32be) (utf16->string (uptr->bytes/4-byte-nul v) 'big #t)]))] [(utf-32be) (utf16->string (uptr->bytes/4-byte-nul v) 'big #t)]))]
[else [else
;; Disable interrupts to avoid a GC: ;; Disable interrupts to avoid a GC:
(with-interrupts-disabled (with-interrupts-disabled*
;; Special treatment is needed for 'scheme-object, since the ;; Special treatment is needed for 'scheme-object, since the
;; host Scheme rejects the use of 'scheme-object with ;; host Scheme rejects the use of 'scheme-object with
;; `foreign-ref` ;; `foreign-ref`
@ -1086,7 +1086,7 @@
"atomic destination" orig-p)] "atomic destination" orig-p)]
[else [else
;; Disable interrupts to avoid a GC: ;; Disable interrupts to avoid a GC:
(with-interrupts-disabled (with-interrupts-disabled*
;; Special treatment is needed for 'scheme-object, since ;; Special treatment is needed for 'scheme-object, since
;; the host Scheme rejects the use of 'scheme-object with ;; the host Scheme rejects the use of 'scheme-object with
;; `foreign-set!` ;; `foreign-set!`
@ -1133,7 +1133,7 @@
"destination" to "destination" to
"source" from)])] "source" from)])]
[else [else
(with-interrupts-disabled (with-interrupts-disabled*
(let ([to (+ (cpointer*-address to) to-offset)] (let ([to (+ (cpointer*-address to) to-offset)]
[from (+ (cpointer*-address from) from-offset)]) [from (+ (cpointer*-address from) from-offset)])
(cond (cond
@ -1275,7 +1275,7 @@
(raise-arguments-error 'memset "cannot set non-atomic" (raise-arguments-error 'memset "cannot set non-atomic"
"destination" to)] "destination" to)]
[else [else
(with-interrupts-disabled (with-interrupts-disabled*
(let ([to (fx+ (cpointer*-address to) to-offset)]) (let ([to (fx+ (cpointer*-address to) to-offset)])
(let loop ([to to] [len len]) (let loop ([to to] [len len])
(unless (fx= len 0) (unless (fx= len 0)
@ -1420,7 +1420,7 @@
(define/who (free p) (define/who (free p)
(let ([p (unwrap-cpointer who p)]) (let ([p (unwrap-cpointer who p)])
(with-interrupts-disabled (with-interrupts-disabled*
(foreign-free (cpointer-address p))))) (foreign-free (cpointer-address p)))))
(define-record-type (cpointer/cell make-cpointer/cell cpointer/cell?) (define-record-type (cpointer/cell make-cpointer/cell cpointer/cell?)
@ -1618,13 +1618,13 @@
(make-ftype-pointer ,id p)))) (make-ftype-pointer ,id p))))
ids) ids)
'())))]) '())))])
(let* ([wb (with-interrupts-disabled (let* ([wb (with-interrupts-disabled*
(weak-hash-ref ffi-expr->code expr #f))] (weak-hash-ref ffi-expr->code expr #f))]
[code (if wb (car wb) #!bwp)]) [code (if wb (car wb) #!bwp)])
(if (eq? code #!bwp) (if (eq? code #!bwp)
(let ([code (eval/foreign expr (if call? 'comp-ffi-call 'comp-ffi-back))]) (let ([code (eval/foreign expr (if call? 'comp-ffi-call 'comp-ffi-back))])
(hashtable-set! ffi-code->expr (car code) expr) (hashtable-set! ffi-code->expr (car code) expr)
(with-interrupts-disabled (with-interrupts-disabled*
(weak-hash-set! ffi-expr->code expr (weak-cons code #f))) (weak-hash-set! ffi-expr->code expr (weak-cons code #f)))
code) code)
code)))] code)))]
@ -1667,24 +1667,24 @@
[proc [proc
(case-lambda (case-lambda
[() [()
(c->s out-type (with-interrupts-disabled (proc)))] (c->s out-type (with-interrupts-disabled* (proc)))]
[(orig-a) [(orig-a)
(let ([a (unwrap orig-a (car in-types))]) (let ([a (unwrap orig-a (car in-types))])
(c->s out-type (retain (c->s out-type (retain
orig-a orig-a
(with-interrupts-disabled (proc (unpack a (car in-types)))))))] (with-interrupts-disabled* (proc (unpack a (car in-types)))))))]
[(orig-a orig-b) [(orig-a orig-b)
(let ([a (unwrap orig-a (car in-types))] (let ([a (unwrap orig-a (car in-types))]
[b (unwrap orig-b (cadr in-types))]) [b (unwrap orig-b (cadr in-types))])
(c->s out-type (retain (c->s out-type (retain
orig-a orig-b orig-a orig-b
(with-interrupts-disabled (with-interrupts-disabled*
(proc (unpack a (car in-types)) (unpack b (cadr in-types)))))))] (proc (unpack a (car in-types)) (unpack b (cadr in-types)))))))]
[(orig-a orig-b orig-c) [(orig-a orig-b orig-c)
(let ([a (unwrap orig-a (car in-types))] (let ([a (unwrap orig-a (car in-types))]
[b (unwrap orig-b (cadr in-types))] [b (unwrap orig-b (cadr in-types))]
[c (unwrap orig-c (caddr in-types))]) [c (unwrap orig-c (caddr in-types))])
(c->s out-type (with-interrupts-disabled (c->s out-type (with-interrupts-disabled*
(retain (retain
orig-a orig-b orig-c orig-a orig-b orig-c
(proc (unpack a (car in-types)) (proc (unpack a (car in-types))
@ -1697,21 +1697,21 @@
[d (unwrap orig-d (cadddr in-types))]) [d (unwrap orig-d (cadddr in-types))])
(c->s out-type (retain (c->s out-type (retain
orig-a orig-b orig-c orig-d orig-a orig-b orig-c orig-d
(with-interrupts-disabled (with-interrupts-disabled*
(proc (unpack a (car in-types)) (proc (unpack a (car in-types))
(unpack b (cadr in-types)) (unpack b (cadr in-types))
(unpack c (caddr in-types)) (unpack c (caddr in-types))
(unpack d (cadddr in-types)))))))] (unpack d (cadddr in-types)))))))]
[orig-args [orig-args
(let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)]) (let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)])
(c->s out-type (with-interrupts-disabled (c->s out-type (with-interrupts-disabled*
(retain (retain
orig-args orig-args
(#%apply proc (map (lambda (a t) (unpack a t)) args in-types))))))])] (#%apply proc (map (lambda (a t) (unpack a t)) args in-types))))))])]
[else [else
(lambda orig-args (lambda orig-args
(let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)]) (let ([args (map (lambda (a t) (unwrap a t)) orig-args in-types)])
(c->s out-type (with-interrupts-disabled (c->s out-type (with-interrupts-disabled*
(retain (retain
orig-args orig-args
(#%apply (gen-proc (cpointer-address proc-p)) (#%apply (gen-proc (cpointer-address proc-p))
@ -1743,7 +1743,7 @@
;; result is a struct type; need to allocate space for it ;; result is a struct type; need to allocate space for it
(normalized-malloc ret-size ret-malloc-mode))]) (normalized-malloc ret-size ret-malloc-mode))])
(when lock (mutex-acquire lock)) (when lock (mutex-acquire lock))
(with-interrupts-disabled (with-interrupts-disabled*
(when blocking? (currently-blocking? #t)) (when blocking? (currently-blocking? #t))
(retain (retain
orig-args orig-args

View File

@ -1,4 +1,16 @@
;; Like `with-interrupts-disabled`, but with no winders
;; and ways returning a single value. Avoiding winders
;; is important in "foreign.ss" so htat callbacks do
;; not return to a world with Scheme-level winders, which
;; will not interact correctly with engines.
(define-syntax-rule (with-interrupts-disabled* e0 e ...)
(begin
(disable-interrupts)
(let ([v (begin e0 e ...)])
(enable-interrupts)
v)))
;; Enabling uninterrupted mode defers a timer callback ;; Enabling uninterrupted mode defers a timer callback
;; until leaving uninterrupted mode. This is the same ;; until leaving uninterrupted mode. This is the same
;; as disabling and enabling interrupts at the Chez ;; as disabling and enabling interrupts at the Chez

View File

@ -95,7 +95,7 @@
(fx= gen (collect-maximum-generation))) (fx= gen (collect-maximum-generation)))
(reachable-size-increments-callback compute-size-increments)) (reachable-size-increments-callback compute-size-increments))
(when (and (= gen (collect-maximum-generation)) (when (and (= gen (collect-maximum-generation))
(current-engine-state)) (currently-in-engine?))
;; This `set-timer` doesn't necessarily penalize the right thread, ;; This `set-timer` doesn't necessarily penalize the right thread,
;; but it's likely to penalize a thread that is allocating quickly: ;; but it's likely to penalize a thread that is allocating quickly:
(set-timer 1)) (set-timer 1))

View File

@ -12,7 +12,6 @@
[make-engine rumble:make-engine] [make-engine rumble:make-engine]
[engine-timeout rumble:engine-timeout] [engine-timeout rumble:engine-timeout]
[engine-return rumble:engine-return] [engine-return rumble:engine-return]
[current-engine-state rumble:current-engine-state]
[call-with-engine-completion rumble:call-with-engine-completion] [call-with-engine-completion rumble:call-with-engine-completion]
[make-condition rumble:make-condition] [make-condition rumble:make-condition]
[condition-wait rumble:condition-wait] [condition-wait rumble:condition-wait]
@ -132,7 +131,6 @@
'make-engine rumble:make-engine 'make-engine rumble:make-engine
'engine-timeout rumble:engine-timeout 'engine-timeout rumble:engine-timeout
'engine-return rumble:engine-return 'engine-return rumble:engine-return
'current-engine-state (lambda (v) (rumble:current-engine-state v))
'call-with-engine-completion rumble:call-with-engine-completion 'call-with-engine-completion rumble:call-with-engine-completion
'set-ctl-c-handler! rumble:set-ctl-c-handler! 'set-ctl-c-handler! rumble:set-ctl-c-handler!
'poll-will-executors poll-will-executors 'poll-will-executors poll-will-executors

View File

@ -280,8 +280,6 @@
'condition-broadcast (lambda args 'condition-broadcast (lambda args
(error "condition-broadcast: not ready")) (error "condition-broadcast: not ready"))
'threaded? (lambda () #f) 'threaded? (lambda () #f)
'current-engine-state (lambda args
(error "current-engine state: not ready"))
'make-mutex (lambda () (make-semaphore 1)) 'make-mutex (lambda () (make-semaphore 1))
'mutex-acquire (lambda (s) (semaphore-wait s)) 'mutex-acquire (lambda (s) (semaphore-wait s))
'mutex-release (lambda (s) (semaphore-post s)) 'mutex-release (lambda (s) (semaphore-post s))

View File

@ -36,7 +36,6 @@
make-engine make-engine
engine-timeout engine-timeout
engine-return engine-return
current-engine-state
call-with-engine-completion call-with-engine-completion
current-process-milliseconds current-process-milliseconds
set-ctl-c-handler! set-ctl-c-handler!

View File

@ -33,7 +33,9 @@
(make-initial-thread (lambda () (make-initial-thread (lambda ()
(set-place-host-roots! initial-place (host:current-place-roots)) (set-place-host-roots! initial-place (host:current-place-roots))
(thunk))) (thunk)))
(poll-and-select-thread! 0)) (call-with-engine-completion
(lambda (done)
(poll-and-select-thread! 0))))
;; Initializes the thread system in a new place: ;; Initializes the thread system in a new place:
(define (call-in-another-main-thread c thunk) (define (call-in-another-main-thread c thunk)
@ -41,8 +43,8 @@
(set-root-custodian! c) (set-root-custodian! c)
(init-system-idle-evt!) (init-system-idle-evt!)
(init-future-place!) (init-future-place!)
(call-in-main-thread thunk) (init-schedule-counters!)
(init-schedule-counters!)) (call-in-main-thread thunk))
;; ---------------------------------------- ;; ----------------------------------------