Skip to content

Commit

Permalink
Syntax cache: Changes to mitigate issue #512
Browse files Browse the repository at this point in the history
Although I'm not yet sure these changes /solve/ #512 -- I'd like to
confirm with an example problem file -- I think they mitigate it.

Certainly they help with e.g. opening a few dozen file in the
typed-racket-more collection with racket-xp-mode enabled. With that, I
see current-memory-use do the usual "sawtooth wave" -- rising until a
GC, then falling. Although Racket seems to delay releasing memory back
to the OS, until sufficient major GCs take place, eventually I do see
that happen, too.

The changes:

1. Eliminate hash-table for online-check-syntax.

The hash-table could accumulate online-check-syntax items for sources
other than the source being checked.

Instead use with-intercepted-logging, a parameter, and put the results
in the cache-entry. Something like this is probably what I should have
done in the first place when implementing #451.

2. Change the syntax cache to be able to evict items on major GC.

This works by wrapping the cache entries in an ephemeron whose value
is a namespace.

This is fairly chunky. Nothing is evicted until a major GC. And then
perhaps more than necessary is evicted. However I spent a fair amount
of time trying and rejecting some other ideas.
  • Loading branch information
greghendershott committed Feb 2, 2021
1 parent d1cbeb7 commit 3e63bdc
Show file tree
Hide file tree
Showing 4 changed files with 239 additions and 159 deletions.
13 changes: 6 additions & 7 deletions racket/commands/check-syntax.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
racket/class
drracket/check-syntax
"../imports.rkt"
(only-in "../online-check-syntax.rkt"
[get get-online-check-syntax-messages])
"../online-check-syntax.rkt"
"../syntax.rkt"
"../util.rkt")

Expand Down Expand Up @@ -59,6 +58,8 @@
(λ () (call-with-semaphore
sema
(λ ()
(log-racket-mode-debug "(current-memory-use) ~v"
(current-memory-use))
(hash-remove! ht path-str))))))))

;; Note: Instead of using the `show-content` wrapper, we give already
Expand Down Expand Up @@ -271,11 +272,9 @@
(define/public (get-annotations)
;; Obtain any online-check-syntax log message values and treat
;; them as mouse-overs.
(for ([v (in-set (get-online-check-syntax-messages src))])
(match-define (list beg end string-or-thunk) v)
(define (force v) (if (procedure? v) (v) v))
(send this syncheck:add-mouse-over-status
"" beg end (force string-or-thunk)))
(for ([v (in-set (current-online-check-syntax))])
(match-define (list beg end str) v)
(send this syncheck:add-mouse-over-status "" beg end str))

;; Convert ht-defs/uses to a list of defs, each of whose uses
;; are sorted by positions.
Expand Down
123 changes: 45 additions & 78 deletions racket/online-check-syntax.rkt
Original file line number Diff line number Diff line change
@@ -1,92 +1,59 @@
#lang racket/base

(require racket/match
(require racket/logging
racket/match
racket/set
syntax/parse/define
"util.rkt")

(provide reset!
get)
(provide current-online-check-syntax
with-online-check-syntax)

;;; online-check-syntax logger monitor

;; There exists a protocol for macros to communicate tooltips to
;; DrRacket via a log-message to the logger 'online-check-syntax. This
;; might seem strange, but one motivation for this protocol is that
;; e.g. a type-checker might learn things _during_ expansion that it
;; e.g. a type-checker might learn things during expansion that it
;; would like to show the user -- even if expansion fails.
;;
;; A consideration, for us, is that we cache fully-expanded syntax.
;; Therefore we also need to cache these these logger messages -- they
;; might occur long before our `check-syntax` command is called. To do
;; so our log receiver monitor runs all the time, storing messages in
;; a hash-table where the key is the syntax-source, and the value is
;; simply (set (list beg end string-or-thunk))).
;;
;; Rather than complicate the cache in syntax.rkt, for now I think
;; it's less-worse to keep our own hash-table, here, and have
;; syntax.rkt call `reset!` whenever it invalidates its cache so we
;; know to do same here.
;;
;; Note: When string-or-thunk is the latter, we record it as such.
;; Only force if/when `get` is called, e.g. when our check-syntax is
;; run. [Perhaps in DrRacket this could be delayed even further --
;; until a tooltip would actually be _displayed_. Because we must
;; marshal data to the Emacs front end, we must force sooner. At least
;; delay as long as we can. Not sure if that really helps but it seems
;; simple enough to do so here.]

(define ht (make-hash)) ;(hash/c path? (set/c (list/c nat nat (or/c string? (-> string?))

(define sema (make-semaphore 1))

(define-simple-macro (with-sema e:expr ...+)
(call-with-semaphore sema (λ () e ...)))

(define (reset! src)
(with-sema (hash-remove! ht src)))

(define (record! src beg end string-or-thunk)
(with-sema
(hash-update! ht
src
(λ (v) (set-add v
(list beg end string-or-thunk)))
(set))))

(define (get src)
(sleep 0) ;yield to let receiver-thread handle any pending log events
(with-sema (hash-ref ht src (set))))

(define (receiver-thread)
(define receiver (make-log-receiver (current-logger)
'info 'online-check-syntax))
(for ([event (in-producer sync 'n/a receiver)])
(match-define (vector _level _message stxs _topic) event)
(for ([stx (in-list stxs)])
(let walk ([v (syntax-property stx 'mouse-over-tooltips)])
(match v
;; "The value of the 'mouse-over-tooltips property is
;; expected to be to be a tree of cons pairs (in any
;; configuration)..."
[(cons v more)
(walk v)
(walk more)]
;; "...whose leaves are either ignored or are vectors of the
;; shape:"
[(vector (? syntax? stx)
(? exact-positive-integer? beg)
(? exact-positive-integer? end)
(or (? string? string-or-thunk)
(? procedure? string-or-thunk)))
(record! (syntax-source stx)
beg
end
string-or-thunk)]
;; Expected; quietly ignore
[(or (list) #f) (void)]
;; Unexpected; log warning and ignore
[v (log-racket-mode-warning "unknown online-check-syntax ~v" v)
(void)])))))

(void (thread receiver-thread))
(define current-online-check-syntax (make-parameter (mutable-set)))

(define-simple-macro (with-online-check-syntax source:expr e:expr ...+)
(call-with-online-check-syntax source (λ () e ...)))

(define (call-with-online-check-syntax source proc)
(current-online-check-syntax (mutable-set)) ;reset
(with-intercepted-logging (make-interceptor source) proc
'info 'online-check-syntax))

(define ((make-interceptor src) event)
(match-define (vector _level _message stxs _topic) event)
(for ([stx (in-list stxs)])
(let walk ([v (syntax-property stx 'mouse-over-tooltips)])
(match v
;; "The value of the 'mouse-over-tooltips property is
;; expected to be to be a tree of cons pairs (in any
;; configuration)..."
[(cons v more)
(walk v)
(walk more)]
;; "...whose leaves are either ignored or are vectors of the
;; shape:"
[(vector (? syntax? stx)
(? exact-positive-integer? beg)
(? exact-positive-integer? end)
(or (? string? string-or-thunk)
(? procedure? string-or-thunk)))
(when (equal? src (syntax-source stx))
;; Force now; the resulting string will likely use less
;; memory than a thunk closure.
(define (force v) (if (procedure? v) (v) v))
(define str (force string-or-thunk))
(set-add! (current-online-check-syntax)
(list beg end str)))]
;; Expected; quietly ignore
[(or (list) #f) (void)]
;; Unexpected; log warning and ignore
[v (log-racket-mode-warning "unknown online-check-syntax ~v" v)
(void)]))))
2 changes: 1 addition & 1 deletion racket/repl.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
;; possibly entering module->namespace.
(set-session! (current-session-id) maybe-mod #f)
;; 3. If module, require and enter its namespace, etc.
(with-expanded-syntax-caching-evaluator maybe-mod
(with-expanded-syntax-caching-evaluator
(when (and maybe-mod mod-path)
(parameterize ([current-module-name-resolver module-name-resolver-for-run])
;; When exn:fail during module load, re-run.
Expand Down

0 comments on commit 3e63bdc

Please sign in to comment.