Simulation is useful not only for verifying the correctness of a
proposed machine design but also for measuring the machine's
performance. For example, we can install in our simulation program a
meter
that measures the number of stack operations used in a
computation. To do this, we modify our simulated stack to keep track
of the number of times registers are saved on the stack and the
maximum depth reached by the stack, and add a message to the stack's
interface that prints the statistics, as shown below.
We also add an operation to the basic machine model to print the
stack statistics, by initializing
the-ops
the_ops
in
make-new-machine
make_new_machine
to
Original | JavaScript |
(list (list 'initialize-stack (lambda () (stack 'initialize))) (list 'print-stack-statistics (lambda () (stack 'print-statistics)))) | list(list("initialize_stack", () => stack("initialize")), list("print_stack_statistics", () => stack("print_statistics"))); |
Original | JavaScript |
(define (make-stack) (let ((s '()) (number-pushes 0) (max-depth 0) (current-depth 0)) (define (push x) (set! s (cons x s)) (set! number-pushes (+ 1 number-pushes)) (set! current-depth (+ 1 current-depth)) (set! max-depth (max current-depth max-depth))) (define (pop) (if (null? s) (error "Empty stack - - POP") (let ((top (car s))) (set! s (cdr s)) (set! current-depth (- current-depth 1)) top))) (define (initialize) (set! s '()) (set! number-pushes 0) (set! max-depth 0) (set! current-depth 0) 'done) (define (print-statistics) (newline) (display (list 'total-pushes '= number-pushes 'maximum-depth '= max-depth))) (define (dispatch message) (cond ((eq? message 'push) push) ((eq? message 'pop) (pop)) ((eq? message 'initialize) (initialize)) ((eq? message 'print-statistics) (print-statistics)) (else (error "Unknown request - - STACK" message)))) dispatch)) | function make_stack() { let stack = null; let number_pushes = 0; let max_depth = 0; let current_depth = 0; function push(x) { stack = pair(x, stack); number_pushes = number_pushes + 1; current_depth = current_depth + 1; max_depth = math_max(current_depth, max_depth); return "done"; } function pop() { if (is_null(stack)) { error("empty stack -- pop"); } else { const top = head(stack); stack = tail(stack); current_depth = current_depth - 1; return top; } } function initialize() { stack = null; number_pushes = 0; max_depth = 0; current_depth = 0; return "done"; } function print_statistics() { display("total pushes = " + stringify(number_pushes)); display("maximum depth = " + stringify(max_depth)); } function dispatch(message) { return message === "push" ? push : message === "pop" ? pop() : message === "initialize" ? initialize() : message === "print_statistics" ? print_statistics() : error(message, "unknown request -- stack"); } return dispatch; } |
Exercises 5.15 through 5.19 describe other useful monitoring and debugging features that can be added to the register-machine simulator.
Original | JavaScript |
(set-breakpoint $machine$ $label$ $n$) | set_breakpoint($machine$, $label$, $n$) |
Original | JavaScript |
(set-breakpoint gcd-machine 'test-b 4) | set_breakpoint(gcd_machine, "test_b", 4) |
Original | JavaScript |
(proceed-machine $machine$) | proceed_machine($machine$) |
Original | JavaScript |
(cancel-breakpoint $machine$ $label$ $n$) | cancel_breakpoint($machine$, $label$, $n$) |
Original | JavaScript |
(cancel-all-breakpoints $machine$) | cancel_all_breakpoints($machine$) |