;;; -*- Mode:LISP; Package:(STE global); Fonts:(cptfont); Base:8 -*- ;; Copyright LISP Machine, Inc. 1984 ;; See filename "Copyright" for ;; licensing and release information. ;; A self-contained example of streams software usage for ;; testing the performance of and documenting the LAMBA<->UNIX interface. ;; This code runs in system version 1.120, unix-interface version 12. ;; 10/13/84 00:10:24 -George Carrette. ;; modified for release II beta-test 2/26/85 13:23:09 -George Carrette. ;; To run the tests: ;; (1) Create the C programs by running (CREATE-C-PROGRAMS) ;; These functions illustrate some of the higher level protocals. ;; (2) Create a split-screen with two lisp listeners. ;; Use RUN-C-PROGRAM in the top window, switch to the bottom and ;; use the corresponding lisp function. (defun attached-unix-host () "Returns host object for attached unix-host if it exits otherwise NIL" ;; Relevant variable: ;; si:*other-processors* list of structures of type SI:OTHER-PROCESSOR (dolist (op si:*other-processors*) (let ((host (SI:GET-HOST-FROM-ADDRESS (si:%processor-conf-chaos-address (si:op-proc-conf op)) ':CHAOS))) (if (typep host 'fs:unix-host) (return host))))) (defun temp-unix-path (name type) (fs:make-pathname ':host (attached-unix-host) ':directory "TMP" ':name (string-append (string-upcase si:user-id) "-" name) ':type type)) ;; a simple "null-device" for testing. (defconst *p* (open "UNIX-STREAM-4:")) (defun null-device (message &rest ignored) (selectq message (:tyi 0) (:tyipeek 0) (:which-operations '(:tyo :tyi :tyipeek :untyi :string-out)))) (defconst *null* (closure () #'null-device)) ;; This uses the FILE protocal and EVAL protocal. (defun share-compile-string (name string) "writes out the string as name.c and C compiles it to name" (with-open-file (stream (temp-unix-path name "C") ':out) (princ string stream)) (simple-unix-eval (attached-unix-host) (format nil "cc ~A -o ~A -lshare" (send (temp-unix-path name "C") ':string-for-host) (send (temp-unix-path name ':unspecific) ':string-for-host)))) (defun simple-unix-eval (host command) (with-open-stream (s (chaos:open-stream host (format nil "EVAL ~a" command))) (format t "~&% ~A~%" command) (do ((c (send s ':tyi) (send s ':tyi))) ((null c)) (send standard-output ':tyo (selectq c ((12 15) #\return) (11 #\tab) (t c)))))) (defvar *c-programs* ()) (defun enter-c-program (name string) (setq *c-programs* (delq (ass #'string-equal name *c-programs*) *c-programs*)) (push (list name string) *c-programs*) name) (defun create-c-programs () (dolist (p *c-programs*) (create-c-program (car p)))) (defun create-c-program (x) (let ((p (ass #'string-equal x *c-programs*))) (format t "~&;Writing and compiling ~A.C" (car p)) (apply #'share-compile-string p))) (defun run-c-program (name) (simple-unix-eval (attached-unix-host) (send (temp-unix-path name ':unspecific) ':string-for-host))) ;;; The tests ;;; open loop frequency (defun test-olf (&optional (n 1000.) (stream *p*) &aux time) (setq time (time)) (do ((j 0 (1+ j))) ((= j n) (send stream ':tyo #/S)) (send stream ':tyo #/?)) (list (quotient n (quotient (time-difference (time) time) 60.0)) "cycles per second")) (enter-c-program "OLFT" ' |//* program for open-loop sink response *// #include main() {int f,n; char c[1]; f = open("//dev//ttyl4",2); if (f < 0) {printf(/"open lost\n/"); exit(0);} while(1) { n = read(f,c,1); if (n == 0) {printf("got end of file\n"); exit(1);} if (n < 0) {printf("read lost\n"); exit(0);} if (*c == 'S') {printf("Been told to stop\n"); exit(1);}}} |) ;; the closed loop frequence is the basic "remote-function-call" ;; overhead time. With this implementation it is highly dependant on, ;; and usually limited by the lisp scheduler timing because ;; of the process-wait which encumbers the ':tyi to the unix share tty. ;; As things stand, without adding an interrupt driven process wakeup ;; feature to the lispmachine system, the unix processor can ;; affect a process on the lispmachine in no less than 1/60'th of ;; a second. realtime programming applications needing faster response ;; times should consider more low-level clock-break and scheduler ;; modifications. A faster speciallized remote function call mechanism ;; itself calls for a special microcoded function. However, the ;; following is more than reasonable for any job that takes more ;; than half a second in the unix processor. (defun test-clf (&optional (n 100.) (stream *p*) &aux time) (setq time (time)) (do ((j 0 (1+ j))) ((= j n) (send stream ':tyo #/S) (print (if (eq (send stream ':tyi) #/O) "Unix process stopped ok" "Unix process failed to reply to stop"))) (send stream ':tyo #/?) (send stream ':tyi)) (list (quotient n (quotient (time-difference (time) time) 60.0)) "cycles per second")) (enter-c-program "CLFT" ' |//* program freq.c for closed-loop. *// #include main() {int f,n; char c[1]; f = open("//dev//ttyl4",2); if (f < 0) {printf("open lost\n"); exit(0);} while(1) { n = read(f,c,1); if (n == 0) {printf("got end of file\n"); exit(1);} if (n < 0) {printf("read lost\n");exit(0);} if (*c == 'S') {printf("Been told to stop\n"); c[0] = 'O'; write(f,c,1); exit(1);} n = write(f,c,1); if (n < 0) {printf("write lost\n"); exit(0);}}} |) (defsetf si:share-mem-read si:share-mem-write) (defun share-mem-read-single-float (addr) (float-68000-32b (si:share-mem-read addr))) (defmacro share-mem-read-bit (j) `(ldb (byte 1 (remainder ,j 32)) (si:share-mem-read (quotient ,j 32)))) (defun float-68000-32b (x) "Take 32bits, a 68000 float, and return a lisp float object" ;; note: This takes byte reversal into account. It doesnt try to be ;; efficient in its use of lispmachine arithmetic. (// (* (expt -1 (ldb #o3701 x)) (expt 2.0 (- (ldb #o3007 x) #o100)) (+ (ldb #o2010 x) (ash (+ (ldb #o1010 x) (ash (ldb #o0010 x) 8.)) 8.))) #o100000000)) (defun 68000-32b-float (x &aux sign exp frac) "Take a lispmachine floating point number and return 32 bits suitable for the 68000" (cond ((zerop x) 0) ('else (cond ((small-floatp x) (cond ((< x 0.0) (setq sign 1) (setq x (- x))) (t (setq sign 0))) (setq exp (+ (- (si:%short-float-exponent x) #o101) #o100)) (setq frac (ash (- (si:%short-float-mantissa x) (expt 2 16)) (- 23 16)))) ((floatp x) (cond ((< x 0.0) (setq sign 1) (setq x (- x))) (t (setq sign 0))) (setq exp (+ (- (si:%single-float-exponent x) #o2001) 127)) (setq frac (ash (- (si:%single-float-mantissa x) (expt 2 30)) (- 23 30)))) (t (ferror nil "Not a floating point number: ~S" x))) (ferror nil "foo, work on this tommorow")))) (defun test-inc-loop (&optional (n 100.) &aux time) (setq time (time)) (do ((j 0 (1+ j))(value)) ((= j n) (send *p* ':tyo #/S) (print (if (eq (send *p* ':tyi) #/O) "Unix process stopped ok" "Unix process failed to reply to stop"))) (setq value (test-inc-1 j)) (or (= value (1+ j)) (format t "~&;Error, expecting ~D, got ~D" (1+ j) value))) (list (quotient n (quotient (time-difference (time) time) 60.0)) "cycles per second")) (defun test-inc-1 (integer) "When the program test-inc is compiled on a unix system with cc test-inc.c -lshare and then executed, you can call (test-inc n) and it will write the integer n into the shared-array area, signal the unix process to do the computation, wait for the computation to complete, then return the result, which is N+1 in this case." (si:share-mem-write 0 integer) (send *p* ':tyo #/?) (send *p* ':tyi) (si:share-mem-read 0)) (enter-c-program "INCT" ' |//* program test-inc *// #include #include main() {int f,n,*p,val; char c[1]; f = open("//dev//ttyl4",2); if (f < 0) {printf("open lost\n"); exit(0);} if (share_setup() < 0) {printf("share setup lost\n"); exit(0);} p = (int *) sharebase; while(1) { n = read(f,c,1); if (n == 0) {printf("got end of file\n"); exit(1);} if (n < 0) {printf("read lost\n");exit(0);} if (*c == 'S') {printf("Been told to stop\n"); c[0] = 'O'; write(f,c,1); exit(1);} val = p[0]; val = SWAB32(val)+1; p[0] = SWAB32(val); n = write(f,c,1); if (n < 0) {printf("write lost\n"); exit(0);}}} |) ;; these test values are probably wrong (i.e. TOO LOW) for Release II. ;; 2/26/85 13:33:07 -gjc ;; (test-inc-loop) 20 Hz. ;; results: ;; (test-clf 100. *p*) 52.2 Hz. using freq.c ;; (test-clf 10000. *null*) 6.5 KHz. ;; (test-olf 1000. *p*) 303.3 Hz. Using cat /dev/ttyl4 > /dev/null ;; (test-olf 1000. *p*) 220.0 Hz Using freqc.c ;; (test-olf 10000. *null*) 9.8 Khz.