1. 程式人生 > >5.2.4 監控機器的效能

5.2.4 監控機器的效能

5.2.4 監控機器的效能
模擬是有用的,不僅對於一個假定的機器的設計的正確性進行驗證,而且
對於度量機器的效能。例如,在我們的模擬程式中,我們能夠安裝一個
測量器,它能度量一個計算中的棧操作所使用的次數。為了做到這一點,我們
修改了我們的模擬的棧,來跟蹤被儲存在棧上的次數暫存器的值,和棧達到
的最大深度,並且加一個訊息到棧的介面,來打印出棧的統計資訊,如下所示。
我們也加一個操作到基本的機器模型中來列印棧的統計資訊。通過在make-new-machine中
把 the-ops 初始化到如下的結構中。

(list  (list  'initialize-stack   (lambda  ()  (stack  'initialize)))  
       (list  'print-stack-statistics  (lambda () (stack  'print-statistics))))

這裡有make-stack的新版本的程式:

(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  maxdepth))) 
         (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
     )
)

練習5.14到練習5.19描述了其它的有用的監控與呼叫特性,它能被新增到
暫存器機器的模擬器中。

練習5.14
使用在圖5.11中顯示的階乘機器,對於明顯的很小的n值,度量為了計算n的階乘,
需要的棧的最大深度和壓棧的次數。從你的資料,來確定壓棧操作的總次數和棧的最大深度的
以n為自變數的公式,在計算n的階乘時,任何一個n都大於1。注意,這些中的任何一個都是n
的線性函式,因此能被兩個常數確定。為了得以統計資訊的列印,你將不得不給階乘的機器
以實際 的引數,以帶有初始化棧和列印統計資訊的指令。你可能也要修改機器,讓它來重複地讀取n的值,計算階乘,然後列印結果。(正如我們在圖5.4中的求最大公約數的機器中的做法那樣),所以你將不必重複地呼叫 get-register-contents,set-register-contents!,和start.


練習5.15
新增一個指令的計算到暫存器機器的模擬之中。也就是讓機器的模型保持著對已執行的指令的數量進行跟蹤。擴充套件機器的模型的介面來接受一個新的訊息,它打印出指令的數量和重設為零。

練習5.16
為了對指令進行跟蹤,對模擬器設定一個實際引數。也就是在任何一個指令執行之前,
模擬器應該打印出指令的文字。讓機器模型接受trace-on 和trace-off訊息,來把跟蹤
開啟或者關閉。

練習5.17
擴充套件練習5.16中的指令跟蹤,為了在列印一個指令之前,模擬器打印出在控制器序列中的指令
與之相關聯的標籤。以一種方式實現這個任務時要小心了,不要把它和練習5.15中的指令計數
弄混亂了。你將不得不讓模擬器提供必要的標籤資訊。

練習5.18
修改5.2.1部分中的make-register程式,為了讓暫存器能被跟蹤。暫存器應該接受開啟或者關閉
跟蹤的訊息。當一個暫存器被跟蹤時,賦一個值給暫存器時應該列印暫存器的名稱,暫存器的舊值,被賦的新的值。擴充套件機器模型的介面,允許你能夠開啟與關閉對特定的暫存器的跟蹤。

練習5.19
阿麗莎要一個斷點的功能特性存在於模擬器中,為了能夠幫助她除錯機器設計。
你被安排為她做這個功能。當模擬器停下來時,她要能夠指定在控制器序列中的一個地方,
並且允許她檢查機器的狀態。你將要實現一個程式

(set-breakpoint  <machine>  <label>   <n>)

這是在給定的標籤後面的第n條指令之前設定一個斷點。例如:

(set-breakpoint  gcd-machine  'test-b   4)

這是在對暫存器a賦值之前在gcd-machine中安裝了一個斷點。當模擬器到達了斷點
處,它應該打印出標籤和斷點的偏移量並且停止執行指令。然後阿麗莎能夠使用
get-register-contents和set-register-contents!來操縱被模擬的機器的狀態。她應該
能繼續執行指令通過發出如下的指令:

(proceed-machine  <machine>)

她應該也能夠取消一個特定的斷點,通過如下的程式:

(cancel-breakpoint  <machine>   <label>   <n>)

或者是取消所有的斷點,通過如下的程式:

(cancel-all-breakpoints  <machine>)