imperative-syndicate versions

This commit is contained in:
Tony Garnock-Jones 2018-04-29 23:16:07 +01:00
parent 1216fba58b
commit da3f737079
9 changed files with 456 additions and 3 deletions

View File

@ -10,6 +10,7 @@
- echoserver.erl is a matching ping server in Erlang
- echo-server-minimart-tcp-driver.rkt is a server using Minimart's TCP driver
- echo-server-prospect-tcp-driver.rkt is a server using Prospect's TCP driver
- echo-server-imperative-syndicate-tcp-driver.rkt is a server using Imperative Syndicate's TCP driver
- echo-server.rkt is a server using Minimart, but eschewing the TCP driver
- plain-racket-server.rkt is a server using built-in Racket threads
- uvserver.c is a server written in C with libuv
@ -20,11 +21,14 @@
symbols instead of fixnums to identify peers.
- internal-latency-prospect.rkt is the same, but using Prospect
instead of Minimart.
- internal-latency-imperative-syndicate.rkt is the same, but using
Imperative Syndicate instead of Minimart.
- observe-all-minimart.rkt, observe-all-prospect.rkt,
sum-all-minimart.rkt and sum-all-prospect.rkt measure the costs of
presence notification and processing in Minimart and Prospect
worlds, respectively.
observe-all-imperative-syndicate.rkt, sum-all-minimart.rkt,
sum-all-prospect.rkt, and sum-all-imperative-syndicate.rkt measure
the costs of presence notification and processing in Minimart,
Prospect, and Imperative Syndicate worlds, respectively.
- pingpong.rkt and pingpong.erl are simple measurements of Racket's
and Erlang's built-in thread communication latency, respectively.

View File

@ -0,0 +1,92 @@
#lang imperative-syndicate/test-implementation
;; Measurement of *broadcast* message delivery latency.
(require logbook)
(message-struct ping (src dst timestamp))
(message-struct pong (timestamp))
(define (send-ping! src dst)
(send! (ping src dst (current-inexact-milliseconds))))
(define (run #:echoer-count [echoer-count 100]
#:run-time [run-time 10000])
(define total-latency 0)
(define total-roundtrips 0)
(define boot-start-time (current-inexact-milliseconds))
(define run-start-time #f)
(define (rate-at count)
;; count is the number of roundtrips
;; each roundtrip involves (+ echoer-count 1) messages
;; we want messages per second
(/ (* count (+ echoer-count 1)) ;; echoer-count pings and one pong per roundtrip
(/ total-latency 1000.0) ;; latency in seconds
))
(test-case
[(for [(id (in-range echoer-count))]
(spawn (on (message (ping $src $dst $stamp))
(when (= dst id) (send! (pong stamp))))))
(let ((src echoer-count)
(dst 0))
(spawn (on-start
(set! run-start-time (current-inexact-milliseconds))
(send-ping! src dst))
(on (message (pong $start-time))
(define stop-time (current-inexact-milliseconds))
;; TODO: is there a way of reducing the measurement error here,
;; perhaps by recording against run-start-time instead of start-time, somehow?
;; TODO: first, characterize the measurement error
(define delta (- stop-time start-time))
(set! total-latency (+ total-latency delta))
(set! total-roundtrips (+ total-roundtrips 1))
(when (zero? (modulo total-roundtrips 10000))
(log-info "After ~a roundtrips, ~a milliseconds; ~a Hz"
total-roundtrips
total-latency
(rate-at total-roundtrips)))
(when (< (- stop-time run-start-time) run-time)
(send-ping! src dst)))))])
(values total-roundtrips
(rate-at total-roundtrips)
(- run-start-time boot-start-time)))
(module+ main
(define t 2000)
(define E (standard-logbook-entry (default-logbook #:verbose? #t) "minimart" "broadcast-latency-imperative-syndicate"))
(define T (logbook-table E "broadcast-latency"
#:column-spec '(number-of-echoers
secs/msg
msgs/sec
boot-delay-ms
secs/process-booted
roundtrip-count
run-duration-ms)))
;; Warmup
(let ()
(run #:echoer-count 1 #:run-time 1000)
(run #:echoer-count 10 #:run-time 1000)
(void))
;; Real run
(for ((n
(list* 1 2 5
(let loop ((n 10))
(if (>= n 30000)
'()
(cons (inexact->exact (round n))
(loop (* n (sqrt (sqrt 2))))))))
))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(define-values (count v boot-delay-ms) (run #:echoer-count n #:run-time t))
(write-logbook-datum! T (list n
(/ 1.0 v)
v
boot-delay-ms
(/ (/ boot-delay-ms 1000.0) n)
count
t))))

View File

@ -0,0 +1,64 @@
#lang imperative-syndicate
(require racket/port)
(require logbook)
(require racket/cmdline)
(require/activate imperative-syndicate/drivers/timer)
(require/activate imperative-syndicate/drivers/tcp)
(begin-for-declarations
(define server-entry-name #f)
(define server-entry-type #f)
(command-line #:program "echo-server-prospect-tcp-driver.rkt"
#:once-each
["--logbook-entry-name" name
"set logbook entry name to use when recording run statistics"
(set! server-entry-name name)]
["--logbook-entry-type" type
"set logbook entry type to use"
(set! server-entry-type type)])
(when (not server-entry-type)
(error 'echo-server "Please supply the --logbook-entry-type command-line argument."))
(define L (default-logbook))
(define E (logbook-entry L "minimart" server-entry-name server-entry-type))
(define Tmem (logbook-table E "server-memory-use" #:column-spec '(time-seconds memory-use)))
(define Tconn (logbook-table E "server-connections" #:column-spec '(time-seconds connection-count)))
(define connection-count 0)
(define first-connection-seen? #f)
(define statistics-poll-interval 2000))
(define (statistician)
(spawn #:name 'statistician
(field [sample-deadline (+ (current-inexact-milliseconds) statistics-poll-interval)])
(on (asserted (later-than (sample-deadline)))
;; (collect-garbage)
;; (collect-garbage)
;; (collect-garbage)
(define now (sample-deadline))
(write-logbook-datum! Tmem (list (/ now 1000.0) (current-memory-use)))
(write-logbook-datum! Tconn (list (/ now 1000.0) connection-count))
(when (and first-connection-seen? (zero? connection-count))
(exit 0))
(sample-deadline (+ (sample-deadline) statistics-poll-interval)))))
(define (listener port-number)
(spawn #:name 'listener
(during/spawn (tcp-connection $id (tcp-listener port-number))
#:name (list 'connection id)
(assert (tcp-accepted id))
(on-start
(set! connection-count (+ connection-count 1))
(set! first-connection-seen? #t))
(on-stop
(set! connection-count (- connection-count 1)))
(on (message (tcp-in id $bs))
(send! (tcp-out id bs))))))
(listener 5999)
(statistician)

View File

@ -27,6 +27,9 @@
["--prospect+tcp"
"use prospect server with TCP driver"
(set! server-variation 'prospect+tcp)]
["--imperative-syndicate+tcp"
"use imperative-syndicate server with TCP driver"
(set! server-variation 'imperative-syndicate+tcp)]
["--racket" "use plain racket server" (set! server-variation 'racket)]
["--other" name "use other server" (set! server-variation name)])
@ -64,6 +67,7 @@
['minimart (format-racket-server-command-line "echo-server.rkt")]
['minimart+tcp (format-racket-server-command-line "echo-server-minimart-tcp-driver.rkt")]
['prospect+tcp (format-racket-server-command-line "echo-server-prospect-tcp-driver.rkt")]
['imperative-syndicate+tcp (format-racket-server-command-line "echo-server-imperative-syndicate-tcp-driver.rkt")]
['racket (format-racket-server-command-line "plain-racket-server.rkt")]
['erlang
(define erlang-version-command

View File

@ -0,0 +1,87 @@
#lang imperative-syndicate/test-implementation
;; Measurement of message delivery latency.
(require logbook)
(message-struct ping (src dst timestamp))
(define (send-ping! src dst)
(send! (ping src dst (current-inexact-milliseconds))))
(define (run #:echoer-count [echoer-count 100]
#:run-time [run-time 10000])
(define total-latency 0)
(define total-roundtrips 0)
(define boot-start-time (current-inexact-milliseconds))
(define run-start-time #f)
(define (rate-at count)
(/ (* count 2) ;; two messages per roundtrip
(/ total-latency 1000.0) ;; latency in seconds
))
(test-case
[(for [(id (in-range echoer-count))]
(spawn (on (message (ping $src id $stamp))
(send! (ping id src stamp)))))
(let ((src echoer-count)
(dst 0))
(spawn (on-start
(set! run-start-time (current-inexact-milliseconds))
(send-ping! src dst))
(on (message (ping dst src $start-time))
(define stop-time (current-inexact-milliseconds))
;; TODO: is there a way of reducing the measurement error here,
;; perhaps by recording against run-start-time instead of start-time, somehow?
;; TODO: first, characterize the measurement error
(define delta (- stop-time start-time))
(set! total-latency (+ total-latency delta))
(set! total-roundtrips (+ total-roundtrips 1))
(when (zero? (modulo total-roundtrips 10000))
(log-info "After ~a roundtrips, ~a milliseconds; ~a Hz"
total-roundtrips
total-latency
(rate-at total-roundtrips)))
(when (< (- stop-time run-start-time) run-time)
(send-ping! src dst)))))])
(values total-roundtrips (rate-at total-roundtrips) (- run-start-time boot-start-time)))
(module+ main
(define t 2000)
(define E (standard-logbook-entry (default-logbook #:verbose? #t) "minimart" "internal-latency-imperative-syndicate"))
(define T (logbook-table E "internal-latency"
#:column-spec '(number-of-echoers
secs/msg
msgs/sec
boot-delay-ms
secs/process-booted
roundtrip-count
run-duration-ms)))
;; Warmup
(let ()
(run #:echoer-count 1 #:run-time 1000)
(run #:echoer-count 10 #:run-time 1000)
(void))
;; Real run
(for ((n
(list* 1 2 5
(let loop ((n 10))
(if (>= n 30000)
'()
(cons (inexact->exact (round n))
(loop (* n (sqrt (sqrt 2))))))))
))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(define-values (count v boot-delay-ms) (run #:echoer-count n #:run-time t))
(write-logbook-datum! T (list n
(/ 1.0 v)
v
boot-delay-ms
(/ (/ boot-delay-ms 1000.0) n)
count
t))))

View File

@ -0,0 +1,58 @@
#lang imperative-syndicate/test-implementation
;; Measurement of presence processing.
;; Peers observe each other, but do not process the resulting routing events.
(require logbook)
(assertion-struct presence (id))
(define (run #:peer-count [peer-count 100])
(define event-count 0)
(define-values (results cpu-time wall-clock-time gc-time)
(time-apply
(lambda ()
(test-case
[(for [(id (in-range peer-count))]
(spawn (assert (presence id))
(on (asserted (presence $peer))
(set! event-count (+ event-count 1)))))]))
'()))
(values event-count (max 1 (- cpu-time gc-time))))
(module+ main
(define E (standard-logbook-entry (default-logbook #:verbose? #t) "minimart" "observe-all-imperative-syndicate"))
(define T (logbook-table E "presence-processing"
#:column-spec '(number-of-peers
secs/routing-update
routing-updates/sec
secs/peer
peers/sec
event-count
run-duration-ms)))
;; Warmup
(let ()
(run #:peer-count 1)
(run #:peer-count 10)
(void))
;; Real run
(for ((n
(list* 1 2 5
(let loop ((n 10))
(if (>= n 1000)
'()
(cons (inexact->exact (round n))
(loop (* n (sqrt (sqrt 2))))))))
))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(define-values (event-count run-duration-ms) (run #:peer-count n))
(write-logbook-datum! T (list n
(/ (/ run-duration-ms 1000.0) event-count)
(/ event-count (/ run-duration-ms 1000.0))
(/ (/ run-duration-ms 1000.0) n)
(/ n (/ run-duration-ms 1000.0))
event-count
run-duration-ms))))

View File

@ -0,0 +1,82 @@
#lang imperative-syndicate/test-implementation
;; Measurement of presence processing.
;; Peers observe just one distinguished peer, and do not process resulting routing events.
(require logbook)
(provide run)
(assertion-struct client ())
(define (run #:peer-count [peer-count 100] #:client-first? [client-first? #f])
(define event-count 0)
(define-values (results cpu-total-ms wall-ms cpu-gc-ms)
(time-apply
(lambda ()
(test-case
[(define (spawn-client)
(spawn (assert (client))))
(define (spawn-server id)
(spawn (on (asserted (client))
(set! event-count (+ event-count 1)))))
(define (spawn-servers)
(for [(id (in-range (- peer-count 1)))]
(spawn-server id)))
(if client-first?
(begin (spawn-client) (spawn-servers))
(begin (spawn-servers) (spawn-client)))]))
'()))
(values event-count (max 1 (- cpu-total-ms cpu-gc-ms))))
(module+ main
(define E (standard-logbook-entry (default-logbook #:verbose? #t) "minimart" "observe-some-imperative-syndicate"))
(define T-client-first (logbook-table E "presence-processing-narrow-client-first"
#:column-spec '(number-of-peers
secs/routing-update
routing-updates/sec
secs/peer
peers/sec
event-count
run-duration-ms)))
(define T-client-last (logbook-table E "presence-processing-narrow-client-last"
#:column-spec '(number-of-peers
secs/routing-update
routing-updates/sec
secs/peer
peers/sec
event-count
run-duration-ms)))
;; Warmup
(let ()
(run #:peer-count 1)
(run #:peer-count 10)
(void))
;; Real run
(for ((n
#;(list 5)
(list* 2 5
(let loop ((n 10))
(if (>= n 100000)
'()
(cons (inexact->exact (round n))
(loop (* n (sqrt (sqrt 2))))))))
))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(for ((client-first? (list #t #f)))
(define-values (event-count run-duration-ms)
(run #:peer-count n #:client-first? client-first?))
(write-logbook-datum! (if client-first? T-client-first T-client-last)
(list n
(/ (/ run-duration-ms 1000.0) event-count)
(/ event-count (/ run-duration-ms 1000.0))
(/ (/ run-duration-ms 1000.0) n)
(/ n (/ run-duration-ms 1000.0))
event-count
run-duration-ms)))))

View File

@ -14,14 +14,20 @@ racket external-latency.rkt --max-waypoint $MAX_WAYPOINT --uv
## racket external-latency.rkt --max-waypoint $MAX_MINIMART_WAYPOINT --minimart ## don't bother
racket external-latency.rkt --max-waypoint $MAX_MINIMART_WAYPOINT --minimart+tcp
racket external-latency.rkt --max-waypoint $MAX_WAYPOINT --prospect+tcp
racket external-latency.rkt --max-waypoint $MAX_WAYPOINT --imperative-syndicate+tcp
racket external-latency.rkt --max-waypoint $MAX_WAYPOINT --racket
racket internal-latency.rkt
racket internal-latency-prospect.rkt
racket internal-latency-imperative-syndicate.rkt
racket broadcast-latency-prospect.rkt
racket broadcast-latency-imperative-syndicate.rkt
racket observe-all-minimart.rkt
racket observe-all-prospect.rkt
racket observe-all-imperative-syndicate.rkt
racket observe-some-minimart.rkt
racket observe-some-prospect.rkt
racket observe-some-imperative-syndicate.rkt

View File

@ -0,0 +1,56 @@
#lang imperative-syndicate/test-implementation
;; Measurement of presence processing.
;; Peers observe each other, AND ALSO process the resulting routing events.
(require logbook)
(assertion-struct presence (id))
(define (run #:peer-count [peer-count 100])
(define event-count 0)
(define start-time (current-inexact-milliseconds))
(test-case [(for [(id (in-range peer-count))]
(spawn (assert (presence id))
(field [peer-count 0])
(on (asserted (presence $peer))
(set! event-count (+ event-count 1))
(peer-count (+ (peer-count) 1)))))])
(define stop-time (current-inexact-milliseconds))
(define delta (- stop-time start-time))
(values event-count delta))
(module+ main
(define E (standard-logbook-entry (default-logbook #:verbose? #t) "minimart" "sum-all-imperative-syndicate"))
(define T (logbook-table E "presence-processing"
#:column-spec '(number-of-peers
secs/event
events/sec
secs/peer
peers/sec
event-count
run-duration-ms)))
;; Warmup
(let ()
(run #:peer-count 1)
(run #:peer-count 10)
(void))
;; Real run
(for ((n
(list* 1 2 5
(let loop ((n 10))
(if (>= n 1000)
'()
(cons (inexact->exact (round n))
(loop (* n (sqrt (sqrt 2))))))))
))
(collect-garbage)
(collect-garbage)
(collect-garbage)
(define-values (event-count run-duration-ms) (run #:peer-count n))
(write-logbook-datum! T (list n
(/ (/ run-duration-ms 1000.0) event-count)
(/ event-count (/ run-duration-ms 1000.0))
(/ (/ run-duration-ms 1000.0) n)
(/ n (/ run-duration-ms 1000.0))
event-count
run-duration-ms))))