(printf "Stream Tests (current dir must be startup dir)~n") (define (log . args) '(begin (apply printf args) (newline))) (define cs-prog '(define (copy-stream in out) (lambda () (let ([s (make-string 4096)]) (let loop () (let ([l (read-string-avail! s in)]) (log "in: ~a" l) (unless (eof-object? l) (let loop ([p 0][l l]) (let ([r (write-string-avail s out p (+ p l))]) (log "out: ~a" r) (when (< r l) (loop (+ p r) (- l r))))) (loop)))))))) (eval cs-prog) (define test-file (find-executable-path (find-system-path 'exec-file) #f)) (define tmp-file (build-path (find-system-path 'temp-dir) "ZstreamZ")) (define (feed-file out) (let ([p (open-input-file test-file)]) (let loop () (let ([c (read-char p)]) (unless (eof-object? c) (write-char c out) (loop)))))) (define (feed-file/fast out) (let ([p (open-input-file test-file)]) ((copy-stream p out)) (close-input-port p))) (define (check-file in) (let ([p (open-input-file test-file)]) (let loop ([badc 0]) (let ([c (read-char p)] [c2 (read-char in)]) (unless (eq? c c2) (if (= badc 30) (error "check-failed" (file-position p) c c2) (begin (fprintf (current-error-port) "fail: ~a ~s ~s~n" (file-position p) c c2) (loop (add1 badc))))) (unless (eof-object? c) (loop badc)))) (close-input-port p))) (define (check-file/fast in) (let ([p (open-input-file test-file)]) (let loop () (let* ([s (read-string 5000 p)] [s2 (read-string (if (string? s) (string-length s) 100) in)]) (unless (equal? s s2) (error "fast check failed")) (unless (eof-object? s) (loop)))) (close-input-port p))) (define (check-file/fastest in) (let ([p (open-input-file test-file)] [s1 (make-string 5000)] [s2 (make-string 5000)]) (let loop ([leftover 0][startpos 0][pos 0]) (let* ([n1 (if (zero? leftover) (read-string-avail! s1 p) leftover)] [n2 (read-string-avail! s2 in 0 (if (eof-object? n1) 1 n1))]) (unless (if (or (eof-object? n1) (eof-object? n2)) (and (eof-object? n1) (eof-object? n2)) (if (= n2 n1 5000) (string=? s1 s2) (string=? (substring s1 startpos (+ startpos n2)) (substring s2 0 n2)))) (error 'check "failed at ~a (~a@~a ~a)" pos n1 startpos n2)) (unless (eof-object? n1) (loop (- n1 n2) (if (= n1 n2) 0 (+ startpos n2)) (+ pos n2))))) (close-input-port p))) (define portno 40000) (define (setup-mzscheme-echo tcp?) (define p (process* test-file "-q" "-b")) (define s (make-string 256)) (define r #f) (define w #f) (define r2 #f) (define w2 #f) (thread (copy-stream (cadddr p) (current-error-port))) (fprintf (cadr p) "(define log void)~n") (fprintf (cadr p) "~s~n" cs-prog) (if tcp? (let ([t (thread (lambda () (define-values (rr ww) (tcp-accept l1)) (define-values (rr2 ww2) (tcp-accept l2)) (set! r rr) (set! w ww) (set! r2 rr2) (set! w2 ww2)))]) (fprintf (cadr p) "(define-values (r w) (tcp-connect \"localhost\" ~a))~n" portno) (fprintf (cadr p) "(define-values (r2 w2) (tcp-connect \"localhost\" ~a))~n" (add1 portno)) (thread-wait t) (fprintf (cadr p) "(begin ((copy-stream r w2)) (exit))~n")) (fprintf (cadr p) "(begin ((copy-stream (current-input-port) (current-output-port))) (exit))~n")) ;; Flush initial output: (read-string (string-length (banner)) (car p)) (sleep 0.3) (when (char-ready? (car p)) (read-string-avail! s (car p))) (sleep 0.3) (when (char-ready? (car p)) (read-string-avail! s (car p))) (if tcp? (values r w r2 w2) p)) (define start-ms 0) (define start-ps-ms 0) (define start-gc-ms 0) (define (start s) (printf s) (set! start-ms (current-milliseconds)) (set! start-gc-ms (current-gc-milliseconds)) (set! start-ps-ms (current-process-milliseconds))) (define (end) (let ([ps-ms (current-process-milliseconds)] [gc-ms (current-gc-milliseconds)] [ms (current-milliseconds)]) (printf "cpu: ~a real: ~a gc ~a~n" (- ps-ms start-ps-ms) (- ms start-ms) (- gc-ms start-gc-ms)))) '(thread (lambda () (let loop () (printf "alive~n") (sleep 1) (loop)))) (start "Quick check:~n") (define p (open-input-file test-file)) (check-file/fast p) (close-input-port p) (end) (start "Quicker check:~n") (define p (open-input-file test-file)) (check-file/fastest p) (close-input-port p) (end) (start "Plain pipe...~n") (define-values (r w) (make-pipe)) (feed-file w) (close-output-port w) (check-file r) (end) (start "Plain pipe, faster...~n") (define-values (r w) (make-pipe)) (feed-file/fast w) (close-output-port w) (check-file/fast r) (end) (start "Plain pipe, fastest...~n") (define-values (r w) (make-pipe)) (feed-file/fast w) (close-output-port w) (check-file/fastest r) (end) (start "Limited pipe...~n") (define-values (r w) (make-pipe 253)) (thread (lambda () (feed-file w) (close-output-port w))) (check-file r) (end) (start "Limited pipe, faster...~n") (define-values (r w) (make-pipe 253)) (thread (lambda () (feed-file/fast w) (close-output-port w))) (check-file/fast r) (end) (start "Limited pipe, fastest...~n") (define-values (r w) (make-pipe 253)) (thread (lambda () (feed-file/fast w) (close-output-port w))) (check-file/fastest r) (end) (start "To file and back:~n") (start " to...~n") (define-values (r w) (make-pipe)) (define p (open-output-file tmp-file 'truncate)) (define t (thread (copy-stream r p))) (feed-file w) (close-output-port w) (thread-wait t) (close-output-port p) (end) (start " back...~n") (define-values (r w) (make-pipe)) (define p (open-input-file tmp-file)) (define t (thread (copy-stream p w))) (thread-wait t) (close-output-port w) (close-input-port p) (check-file r) (end) (start "To file and back, faster:~n") (start " to...~n") (define-values (r w) (make-pipe)) (define p (open-output-file tmp-file 'truncate)) (define t (thread (copy-stream r p))) (feed-file/fast w) (close-output-port w) (thread-wait t) (close-output-port p) (end) (start " back...~n") (define-values (r w) (make-pipe)) (define p (open-input-file tmp-file)) (define t (thread (copy-stream p w))) (thread-wait t) (close-output-port w) (close-input-port p) (check-file/fast r) (end) (start "File back, fastest:~n") (define-values (r w) (make-pipe)) (define p (open-input-file tmp-file)) (define t (thread (copy-stream p w))) (thread-wait t) (close-output-port w) (close-input-port p) (check-file/fastest r) (end) (start "Echo...~n") (define p (setup-mzscheme-echo #f)) (thread (lambda () (feed-file (cadr p)) (close-output-port (cadr p)))) (check-file (car p)) (end) (start "Echo, faster...~n") (define p (setup-mzscheme-echo #f)) (thread (lambda () (feed-file/fast (cadr p)) (close-output-port (cadr p)))) (check-file/fast (car p)) (end) (start "Echo, indirect...~n") (define p (setup-mzscheme-echo #f)) (define-values (rp1 wp1) (make-pipe)) (define-values (rp2 wp2) (make-pipe)) (thread (lambda () ((copy-stream rp1 (cadr p))) (close-output-port (cadr p)))) (thread (lambda () ((copy-stream (car p) wp2)) (close-output-port wp2))) (thread (lambda () (feed-file/fast wp1) (close-output-port wp1))) (check-file/fast rp2) (end) (define l1 (tcp-listen portno)) (define l2 (tcp-listen (add1 portno))) (start "TCP Echo...~n") (define-values (r w r2 w2) (setup-mzscheme-echo #t)) (close-input-port r) (thread (lambda () (feed-file w) (close-output-port w))) (check-file r2) (close-input-port r2) (end) (start "TCP Echo, faster...~n") (define-values (r w r2 w2) (setup-mzscheme-echo #t)) (close-input-port r) (thread (lambda () (feed-file/fast w) (close-output-port w))) (check-file/fast r2) (close-input-port r2) (end) (start "TCP Echo, indirect...~n") (define-values (rp1 wp1) (make-pipe)) (define-values (rp2 wp2) (make-pipe)) (define-values (r w r2 w2) (setup-mzscheme-echo #t)) (close-input-port r) (thread (lambda () ((copy-stream rp1 w)) (close-output-port w))) (thread (lambda () ((copy-stream r2 wp2)) (close-output-port wp2))) (thread (lambda () (feed-file/fast wp1) (close-output-port wp1))) (check-file/fast rp2) (end) (tcp-close l1) (tcp-close l2)