;;; -*- Mode:LISP; Package:METER; Base:8; Readtable:CL -*- ;;; Easy use of this file: ;;; read into buffer and compile, or load an up to data qfasl ;;; then, call (write-page-trace-to-file [file-name]) ;;; After a while, do (setq *stop-page-tracer* t) and ;;; the output file will automatically be closed. ;;; The file should probably be on the local file system, and ;;; certainly has to be a lisp machine file system. ;;; Format of the file: ;;; ;;; 32bits virtual page number ;;; 16bits area number of the pointer at the time of the fault ;;; or 0 if it was ambiguous due to GC ;;; You can do (print-page-trace-file [file-name]) to see the results. ;;; For the area-name printout to be valid, you should do it on ;;; the same machine that wrote the page-trace file, and perhaps ;;; save the output of the print-page-trace-file program. ;;; When the system does a multiple page swap, each page is entered ;;; separatly in the file. Therefore, you can't tell the difference ;;; between pages from a multiple page swap, and sequential faults. ;;; Almost all regions have swaping quantum 3. You can find the ;;; other by running (get-region-swap-quantums). (defun region-number->area-name (region-number) (let ((bits (%p-ldb %%q-pointer (+ (si:%region-origin si:region-bits) region-number)))) (when (not (= (ldb si:%%region-space-type bits) si:%region-space-free)) (aref #'area-name (%p-ldb (byte 16. 0) (+ (si:%region-origin si:region-area-map) region-number)))))) (defun get-region-swap-quantums () (let ((rb (si:%region-origin si:region-bits))) (dotimes (i (si:%region-length si:region-bits)) (let ((q (%p-ldb si:%%region-swapin-quantum (+ rb i))) (type (%p-ldb si:%%region-space-type (+ rb i)))) (when (and (not (= type si:%region-space-free)) (not (= q 3))) (format t "~&~s ~d." (aref #'area-name (%p-ldb (byte 16. 0) (+ (si:%region-origin si:region-area-map) i))) q)))))) ;;callers of %create-physical-page: ;; set-memory-size si:%write-page si:page-in-words-new si:page-in-words-old ;;callers of %change-page-status ; CLEAR-MAR SET-MAR SYSTEM:PAGE-OUT-WORDS ;SI::%MAKE-REGION-READ-ONLY SI::%UNWIRE-PAGE ;SI::%MAKE-PAGE-READ-ONLY SI::%WIRE-PAGE ;SI::REALLY-PAGE-OUT-PAGE SI::%INVALIDATE-REGION-MAPPING ;SI::%DEALLOCATE-PAGES SI::%MAKE-REGION-NOT-READ-ONLY (defvar *page-trace-buffer* (si:make-wireable-array 128. 'art-32b nil)) (defvar *page-trace-out-ptr*) (defun turn-on-page-trace () (when (or (and (> (%pointer *page-trace-buffer*) 0) (< (%pointer-plus *page-trace-buffer* (+ (array-length *page-trace-buffer*) (si:array-data-offset *page-trace-buffer*))) 0)) (and (< (%pointer *page-trace-buffer*) 0) (> (%pointer-plus *page-trace-buffer* (+ (array-length *page-trace-buffer*) (si:array-data-offset *page-trace-buffer*))) 0))) (ferror nil "bad page-trace-buffer")) (without-interrupts (si:%wire-structure *page-trace-buffer*) (si:%page-trace *page-trace-buffer*) (setq *page-trace-out-ptr* (%pointer-plus *page-trace-buffer* (si:array-data-offset *page-trace-buffer*))))) (defun turn-off-page-trace () (si:%page-trace nil) (si:%unwire-structure *page-trace-buffer*)) ; Microsecond clock value ; Virtual address ; Miscellany: ; bit 31: swap-out flag, ; bit 30: stack-group-switch flag ; bit 29: transport flag ; bit 28: scavenge flag ; bits 15-0: micro-pc ; Current function (just randomly picks up @M-AP, hopefully reasonable) (defun print-page-trace () (labels ((aref-32 (array index) (let ((data-offset (+ index (si:array-data-offset array)))) (dpb (%p-ldb-offset (byte 16. 16.) array data-offset) (byte 16. 16.) (%p-ldb-offset (byte 16. 0) array data-offset))))) (do ((i 0 (+ i 4))) ((= i (array-length *page-trace-buffer*))) (format t "~&~10d ~15o ~15a ~15o" (aref-32 *page-trace-buffer* i) (aref-32 *page-trace-buffer* (+ i 1)) (lam:lam-find-closest-sym (+ lam:racmo (ldb (byte 16. 0) (aref-32 *page-trace-buffer* (+ i 2))))) (aref-32 *page-trace-buffer* (+ i 3)))))) micro: (define-micro-function meter:page-trace-ptr () (popj-after-next (m-tem) a-page-trace-ptr) ((m-t) q-pointer m-tem (a-constant (byte-value q-data-type dtp-fix)))) micro: (define-micro-function meter:page-trace-start () (popj-after-next (m-tem) a-page-trace-start) ((m-t) q-pointer m-tem (a-constant (byte-value q-data-type dtp-fix)))) micro: (define-micro-function meter:page-trace-end () (popj-after-next (m-tem) a-page-trace-end) ((m-t) q-pointer m-tem (a-constant (byte-value q-data-type dtp-fix)))) (defun next-page-trace-record () (without-interrupts (let ((out-ptr *page-trace-out-ptr*) (in-ptr (page-trace-ptr))) (cond ((eq out-ptr in-ptr) nil) (t (let ((vadr (%p-ldb (byte 17. 8) (+ out-ptr 1))) (padr (%p-ldb %%q-pointer (+ out-ptr 3))) (swap-out-flag (if (zerop (%p-ldb (byte 1 31.) (+ out-ptr 2))) :in :out))) (when (eq swap-out-flag :in) (setq padr (ldb (byte 14. 8) padr))) (incf out-ptr 4) (when (eq out-ptr (page-trace-end)) (setq out-ptr (page-trace-start))) (setq *page-trace-out-ptr* out-ptr) (values vadr padr swap-out-flag))))))) (defun page-trace-record-available () (not (eq *page-trace-out-ptr* (page-trace-ptr)))) (defun page-trace () (do-forever (process-wait "Page Fault" #'page-trace-record-available) (print (multiple-value-list (next-page-trace-record))))) (defvar *page-trace-window* (make-instance 'tv:window :inside-size '(256. 512.))) (defun process-page-fault (vadr padr direction) padr (let ((screen-array (send *page-trace-window* :screen-array)) (top-margin (send *page-trace-window* :top-margin-size)) (left-margin (send *page-trace-window* :left-margin-size))) (when (and vadr screen-array (send *page-trace-window* :exposed-p)) (setf (ar-2-reverse screen-array (+ (ldb (byte 8 0) vadr) left-margin) (+ (ldb (byte 9 8) vadr) top-margin)) (if (eq direction :out) 0 1))))) (defun initialize-page-trace-window () (let ((phys-pages (floor (aref #'sys:system-communication-area sys:%sys-com-memory-size) 256.)) (screen-array (send *page-trace-window* :screen-array)) (top-margin (send *page-trace-window* :top-margin-size)) (left-margin (send *page-trace-window* :left-margin-size))) (when (and screen-array (send *page-trace-window* :exposed-p)) (do ((pht-index 0 (+ pht-index 2)) (pht-adr (si:%region-origin si:page-table-area)) (end-pht-index (cond ((< %microcode-version-number 1660.) (* phys-pages 4)) (t (si:%region-length si:page-table-area))))) ((= pht-index end-pht-index)) (when (not (zerop (%p-ldb si:%%pht1-valid-bit (+ pht-index pht-adr)))) (let ((vpage (%p-ldb si:%%pht1-virtual-page-number (+ pht-index pht-adr)))) (setf (ar-2-reverse screen-array (+ (ldb (byte 8 0) vpage) left-margin) (+ (ldb (byte 9 8) vpage) top-margin)) 1))))))) (defun watch-page-faults () (send *page-trace-window* :expose) (tv:turn-off-sheet-blinkers *page-trace-window*) (send *page-trace-window* :clear-screen) (without-interrupts (initialize-page-trace-window)) (do-forever (process-wait "Page Fault" #'page-trace-record-available) (process-page-fault))) (defvar *phys-page-trace-window* (make-instance 'tv:window :inside-size '(128. 128.))) (defun watch-physical-page-activity () (send *phys-page-trace-window* :expose) (send (car (send *phys-page-trace-window* :blinker-list)) :set-visibility :off) (send *phys-page-trace-window* :clear-screen) (without-interrupts (initialize-phys-page-trace-window) (setq *page-trace-out-ptr* (page-trace-ptr)) ) (do-forever (process-wait "Page Fault" #'page-trace-record-available) (process-page-fault-physical))) (defun watch-both () (send *phys-page-trace-window* :expose) (send (car (send *phys-page-trace-window* :blinker-list)) :set-visibility :off) (send *phys-page-trace-window* :clear-screen) (without-interrupts (initialize-phys-page-trace-window) (setq *page-trace-out-ptr* (page-trace-ptr)) ) (send *page-trace-window* :expose) (tv:turn-off-sheet-blinkers *page-trace-window*) (send *page-trace-window* :clear-screen) (without-interrupts (initialize-page-trace-window)) (do-forever (process-wait "Page Fault" #'page-trace-record-available) (multiple-value-bind (vpage ppage direction) (next-page-trace-record) (process-page-fault-physical vpage ppage direction) (process-page-fault vpage ppage direction)))) (defun watch-both-clock-function () (send *phys-page-trace-window* :expose) (send (car (send *phys-page-trace-window* :blinker-list)) :set-visibility :off) (send *phys-page-trace-window* :clear-screen) (without-interrupts (initialize-phys-page-trace-window) (setq *page-trace-out-ptr* (page-trace-ptr)) ) (send *page-trace-window* :expose) (tv:turn-off-sheet-blinkers *page-trace-window*) (send *page-trace-window* :clear-screen) (without-interrupts (initialize-page-trace-window)) (pushnew 'page-trace-clock-function si:clock-function-list)) (defun setup-both-windows () (without-interrupts (send *phys-page-trace-window* :expose) (send (car (send *phys-page-trace-window* :blinker-list)) :set-visibility :off) (send *phys-page-trace-window* :clear-screen) (without-interrupts (initialize-phys-page-trace-window) (setq *page-trace-out-ptr* (page-trace-ptr)) ) (send *page-trace-window* :expose) (tv:turn-off-sheet-blinkers *page-trace-window*) (send *page-trace-window* :clear-screen) (without-interrupts (initialize-page-trace-window)))) (defun page-trace-clock-function (&rest ignore) (multiple-value-bind (nil error-p) (ignore-errors (do-forever (multiple-value-bind (vpage ppage direction) (next-page-trace-record) (when (null vpage) (return nil)) (process-page-fault-physical vpage ppage direction) (process-page-fault vpage ppage direction)))) (when error-p (setq si:clock-function-list (remq 'page-trace-clock-function si:clock-function-list))))) (defun phys-page-bit (page) (let ((screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size))) (ar-2-reverse screen-array (+ (ldb (byte 7 0) page) left-margin) (+ (ldb (byte 7 7) page) top-margin)))) (defun set-phys-page-bit (page bit) (let ((screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size))) (as-2-reverse bit screen-array (+ (ldb (byte 7 0) page) left-margin) (+ (ldb (byte 7 7) page) top-margin)))) (defun initialize-phys-page-trace-window (&optional clear-p) (when clear-p (send *phys-page-trace-window* :clear-screen)) (let ((phys-pages (floor (aref #'sys:system-communication-area sys:%sys-com-memory-size) 256.)) (screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size))) (when (and screen-array (send *phys-page-trace-window* :exposed-p)) (do ((pht-index 0 (+ pht-index 2)) (pht-adr (si:%region-origin si:page-table-area)) (end-pht-index (cond ((< %microcode-version-number 1660.) (* phys-pages 4)) (t (si:%region-length si:page-table-area))))) ((= pht-index end-pht-index)) (when (and (not (zerop (%p-ldb si:%%pht1-valid-bit (+ pht-index pht-adr)))) (not (= (%p-ldb si:%%pht1-virtual-page-number (+ pht-index pht-adr)) si:%PHT-DUMMY-VIRTUAL-ADDRESS))) (let ((ppage (%p-ldb si:%%pht2-physical-page-number (+ 1 pht-index pht-adr)))) (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) ppage) left-margin) (+ (ldb (byte 7 7) ppage) top-margin)) 1)))) ))) (defun show-dummy-pages () (let ((phys-pages (floor (aref #'sys:system-communication-area sys:%sys-com-memory-size) 256.)) (screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size))) (when (and screen-array (send *phys-page-trace-window* :exposed-p)) (do ((pht-index 0 (+ pht-index 2)) (pht-adr (si:%region-origin si:page-table-area)) (end-pht-index (cond ((< %microcode-version-number 1660.) (* phys-pages 4)) (t (si:%region-length si:page-table-area))))) ((= pht-index end-pht-index)) (when (and (not (zerop (%p-ldb si:%%pht1-valid-bit (+ pht-index pht-adr)))) (= (%p-ldb si:%%pht1-virtual-page-number (+ pht-index pht-adr)) si:%PHT-DUMMY-VIRTUAL-ADDRESS)) (let ((ppage (%p-ldb si:%%pht2-physical-page-number (+ 1 pht-index pht-adr)))) (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) ppage) left-margin) (+ (ldb (byte 7 7) ppage) top-margin)) 1)))) ))) (defun process-page-fault-physical (vpage ppage direction) (let ((screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size))) (when (and vpage screen-array (send *phys-page-trace-window* :exposed-p)) (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) ppage) left-margin) (+ (ldb (byte 7 7) ppage) top-margin)) (if (eq direction :out) 0 1)) ))) (defun read-a-mem (a-mem-loc) (let ((loc (micro:a-mem-lookup (intern (string a-mem-loc) "MICRO")))) (when (null loc) (ferror nil "unknown a-mem name")) (micro:%read-a-mem loc))) (defun print-ptrs () (do-forever (format t "~&~10s ~10s ~10s ~10s " (read-a-mem 'a-findcore-scan-pointer) (read-a-mem 'a-aging-scan-pointer) (si:read-meter 'si:%count-disk-page-reads) (si:read-meter 'si:%count-disk-page-writes)))) (defun show-findcore-pointer () (let ((screen-array (send *phys-page-trace-window* :screen-array)) (top-margin (send *phys-page-trace-window* :top-margin-size)) (left-margin (send *phys-page-trace-window* :left-margin-size)) (page-number (read-a-mem 'a-findcore-scan-pointer))) (unwind-protect (do-forever (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) page-number) left-margin) (+ (ldb (byte 7 7) page-number) top-margin)) 1) (process-sleep 30.) (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) page-number) left-margin) (+ (ldb (byte 7 7) page-number) top-margin)) 0) (process-sleep 30.)) (setf (ar-2-reverse screen-array (+ (ldb (byte 7 0) page-number) left-margin) (+ (ldb (byte 7 7) page-number) top-margin)) 1)))) (defvar *pht* (si:make-wireable-array #o400 'art-32b nil)) (defvar *ppd* (si:make-wireable-array #o100 'art-32b nil)) (defun page-table-snapshot () (si:%wire-structure *pht*) (si:%wire-structure *ppd*) (without-interrupts (%blt (si:%region-origin si:page-table-area) (%pointer-plus *pht* (si:array-data-offset *pht*)) (array-length *pht*) 1) (%blt (si:%region-origin si:physical-page-data) (%pointer-plus *ppd* (si:array-data-offset *ppd*)) (array-length *ppd*) 1)) (si:%unwire-structure *pht*) (si:%unwire-structure *ppd*)) (defun page-table-ref (a index) (let ((offset (si:array-data-offset a))) (dpb (%p-ldb-offset (byte 16. 16.) a (+ offset index)) (byte 16. 16.) (%p-ldb-offset (byte 16. 0) a (+ offset index))))) (defun find-all-phys-pages () (let ( (unusable 0) (odd-ppd-entries 0) (ppd-entries-pointing-to-invalid 0) (inconsistancies 0) (dummies 0) (used 0) ) (send *phys-page-trace-window* :clear-screen) (dotimes (page (array-length *ppd*)) (let ((ppd-entry (ldb (byte 16. 0) (page-table-ref *ppd* page) ))) (cond ((= ppd-entry #o177777) (set-phys-page-bit page 1) (incf unusable)) ((oddp ppd-entry) (incf odd-ppd-entries)) (t (let ((pht1 (page-table-ref *pht* ppd-entry)) (pht2 (page-table-ref *pht* (1+ ppd-entry)))) (cond ((zerop (ldb si:%%pht1-valid-bit pht1)) (incf ppd-entries-pointing-to-invalid)) ((not (= page (ldb si:%%pht2-physical-page-number pht2))) (incf inconsistancies)) ((= (ldb si:%%pht1-virtual-page-number pht1) si:%PHT-DUMMY-VIRTUAL-ADDRESS) (incf dummies)) (t (set-phys-page-bit page 1) (incf used)))))))) (format t "~&Used ~d; Dummies ~d; Inconsistancies ~d; odd ~d; unusable ~d; Invalid ~d" used dummies inconsistancies odd-ppd-entries unusable ppd-entries-pointing-to-invalid))) ;; evaluate this to turn off multiple page swaps ;; (setf (ldb (byte 1 3) %disk-switches) 0) (defvar *stop-page-tracer*) (defun write-page-trace-to-file (&optional (file-name "lm:pace;page-trace-out.bin")) (setq si:clock-function-list (remq 'page-trace-clock-function si:clock-function-list)) (setq *stop-page-tracer* nil) (process-run-function "Page Tracer" #'(lambda () (with-open-file (stream file-name :direction :output :characters nil) (turn-on-page-trace) (do-forever (process-wait "Page Fault" #'(lambda () (or *stop-page-tracer* (page-trace-record-available)))) (when *stop-page-tracer* (return nil)) (multiple-value-bind (vpage ppage direction) (next-page-trace-record) ppage direction (when (and vpage (not (= vpage #o377777))) (send stream :tyo (ldb (byte 16. 0) vpage)) (send stream :tyo (ldb (byte 16. 16.) vpage)) (send stream :tyo (or (%area-number (lsh vpage 8)) 0)) )) ))))) (defun print-page-trace-file (&optional (file-name "lm:pace;page-trace-out.bin")) (with-open-file (stream file-name :characters nil) (do ((column 0)) (()) (let* ((c0 (send stream :tyi)) (c1 (send stream :tyi)) (area-number (send stream :tyi))) (when (or (null c0) (null c1) (null area-number)) (return nil)) (when (zerop (ldb (byte 1 0) column)) (setq column 0) (format t "~&")) (let ((page (dpb c1 (byte 16. 16.) c0))) (incf column) (format t "~8d ~a~40t" page (area-name area-number))))))) ; shared area 177300000 .. 64 pages ;(defflavor memory-trace ; ((output-stream nil) ; ) ; (si:buffered-input-stream) ; :settable-instance-variables) ;(defmethod (memory-trace :after :init) (ignore) ; (when (null output-stream) ; (ferror nil "must provide output-stream")) (defvar *dirty-page-timer-start*) (defvar *dirty-page-accumulator*) (defvar *page-read-in-times* (make-array (ash 1 17.) :initial-element 0)) (defun print-read-in-times () (dotimes (i (array-length *page-read-in-times*)) (when (not (zerop (aref *page-read-in-times* i))) (format t "<~o ~o>" i (aref *page-read-in-times* i))))) (defun dirty-page-timer () (mapcar #'(lambda (p) (when (string-equal (send p :name) "Page Timer") (send p :kill))) si:all-processes) (si:process-allow-schedule) (array-initialize *page-read-in-times* 0) (setq si:clock-function-list (remq 'page-trace-clock-function si:clock-function-list)) (setq *dirty-page-timer-start* (time)) (setq *dirty-page-accumulator* 0) (process-run-function "Page Timer" #'(lambda () (turn-on-page-trace) (do-forever (process-wait "Page Fault" #'(lambda () (page-trace-record-available))) (multiple-value-bind (vpage ppage direction) (next-page-trace-record) vpage (cond ((eq direction :in) (setf (aref *page-read-in-times* ppage) (time))) ((zerop (aref *page-read-in-times* ppage))) (t (incf *dirty-page-accumulator* (time-difference (time) (aref *page-read-in-times* ppage)))))))))) ;(DEFUN CLEAN-DIRTY-PAGES () ; (DO ((ADR (%REGION-ORIGIN PAGE-TABLE-AREA) (+ ADR 2)) ; (N (TRUNCATE (AREF (SYMBOL-FUNCTION 'SYSTEM-COMMUNICATION-AREA) %SYS-COM-PAGE-TABLE-SIZE) ; 2) ; (1- N)) ; (N-DIRTY 0)) ; ((ZEROP N) ; N-DIRTY) ; (COND ((AND (NOT (ZEROP (%P-LDB %%PHT1-VALID-BIT ADR))) ; (NOT (= (%P-LDB %%PHT1-SWAP-STATUS-CODE ADR) %PHT-SWAP-STATUS-WIRED)) ; (OR (= (%P-LDB %%PHT1-MODIFIED-BIT ADR) 1) ; (= (%P-LDB %%PHT2-MAP-STATUS-CODE (1+ ADR)) ; %PHT-MAP-STATUS-READ-WRITE))) ; (SETQ N-DIRTY (1+ N-DIRTY)) ; (REALLY-PAGE-OUT-PAGE (LSH (%P-LDB %%PHT1-VIRTUAL-PAGE-NUMBER ADR) 8.)))))) (defun print-dirty-page-timer () (let ((start *dirty-page-timer-start*) (acc *dirty-page-accumulator*) (now (time))) (float (/ acc (* (ash (si:system-communication-area si:%sys-com-memory-size) -8) (time-difference now start))))))