[racket] returning self as sync result with struct prop:evt and wrap-evt

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Wed Jun 27 21:31:21 EDT 2012

At Wed, 27 Jun 2012 18:20:45 -0400, Neil Van Dyke wrote:
> Question: If I put a "log-debug" into that "(lambda (self) ...)" proc, 
> looks like the proc is applied every time i call "sync".  If the 
> "log-debug" isn't in there, is the overhead of applying that proc and 
> "wrap-evt" each time I call "sync" practically zero, or would I possibly 
> get better I/O performance with the "letrec" and calling "wrap-evt" only 
> once?

I don't know. Lets try a rough measurement...

Base port is a bytes port with 1,000,000 bytes, loop to eof,
times in msec:

            just read       sync then read
 direct       45 (gc: 0)      325  (gc: 19)
 letrec       51 (gc: 0)      834  (gc: 12)
 self         51 (gc: 0)      1297  (gc: 17)

So, yes, counting just the `sync' overhead, it's roughly 50% slower in
to use `(lambda (self) ...)', though apparently with little extra GC.

In more absolute terms, the overhead is on the order of 1 msec or about
10x the cost to read a byte out of a port. Whether that's "practically
zero" depends on what you're doing with each byte.

----------------------------------------
go.rkt
----------------------------------------
#lang racket
(provide go)

(define N 1000000)

(define (mk-in) (open-input-bytes (make-bytes N 0)))

(define (go mk my-struct-read)
  (define s (mk (mk-in)))
  ;; just read:
  (time
   (let loop ()
     (let ((v (my-struct-read s)))
       (unless (eof-object? v)
         (loop)))))
  (define s2 (mk (mk-in)))
  ;; sync & read::
  (time
   (let loop ()
     (let ((my-evt-result (sync s2)))
       (let ((v (my-struct-read s2)))
         (unless (eof-object? v)
           (loop)))))))

----------------------------------------
direct.rkt
----------------------------------------
#lang racket/base
(require "go.rkt")

(go values read-byte)

----------------------------------------
letrec.rkt
----------------------------------------
#lang racket/base
(require "go.rkt")

(struct my-struct (my-wrapped-evt my-wrapping-evt)
  #:property prop:evt (struct-field-index my-wrapping-evt))

(define (my-struct* my-wrapped-evt)
  (letrec ((my-wrapping-evt (wrap-evt my-wrapped-evt
                                      (lambda (ignored-wrapped-evt)
                                        s)))
           (s (my-struct my-wrapped-evt
                         my-wrapping-evt)))
    s))

(define (my-struct-read s)
   (read-byte (my-struct-my-wrapped-evt s)))

(go my-struct* my-struct-read)

----------------------------------------
self.rkt
----------------------------------------
#lang racket/base
(require "go.rkt")

(struct my-struct (my-wrapped-evt)
   #:property prop:evt (lambda (self)
                         (wrap-evt (my-struct-my-wrapped-evt self)
                                   (lambda (ignored)
                                     self))))

(define (my-struct-read s)
   (read-byte (my-struct-my-wrapped-evt s)))

(go my-struct my-struct-read)


Posted on the users mailing list.