前一節所介紹的計時方法只是一個直接有效的方法,但只能對一段程式碼進行計時。本節將介紹 MATLAB 的「程式計時器」(Profiler,簡稱計時器),它可以分別計算每一個指令所佔用的執行時間,並列出詳細的統計表。尤其當你的函式又呼叫了其他函式,在如此一層包一層的情況下,唯有使用 MATLAB 計時器才能有效地計算出每一個函式所花的時間,並進而進行改進,可能的改進方向是:
如果你的視窗作業系統使用了 Intel 多核心晶片,為了使計時器能夠達到最穩定的結果,你必須先指定 MATLAB 只能使用一個核心,方法如下:
- 對於耗時較久的函式,可以改用較有效率的演算法。
- 盡量儲存目前運算結果,而不要一切重頭算起。
- 盡量改用內建的指令,可以大幅提高效率。
如果你是使用 Linux/Unix 作業系統,可以使用命令列來指定 MATLAB 只能使用一個核心,方法如下:
- 按下 Ctrl-Alt-Delete 以啟動工作管理員。
- 點選「處理程序」分頁。
- 以右鍵點選 MATLAB.exe,並選擇「設定親和性(A)...」。
- 只點選「CPU 0」,使 MATLAB.exe 只能在此核心上執行。
(當你使用完 MATLAB 計時器後,記得將這些設定改回原先的設定。)
- 先使用下列指令找出 MATLAB 所對應的程序編號(Process ID, or PID):
ps -C MATLAB - 假設 PID 是 8674,則我們可以使用下列指令來查詢 MATLAB 可以使用的核心:
taskset -pc 8674 - 最後,我們可以設定 MATLAB 只用一個核心:
taskset -pc 0 8674 MATLAB 計時器的指令是 profile,在其後可加上不同的選項,以代表不同功能。例如,若要對 for 迴圈及所用到的指令分別計時,可以參考下列範例:
執行完上述程式碼後,MATLAB 會將執行所花費時間的統計資料顯示出來,如下圖:
由上圖可得知,mean 指令共被呼叫了 1000 次 ,佔用的 Total Time 是 0.038 秒(包含在 mean 內部所有呼叫其他函式的時間),而 Self Time 只有 0.022 秒,此時間並不包含 mean 函式(在此為 M 檔案)內部呼叫其他函式所花的時間。此外,inv 和 rand 各被呼叫 1000 和 2000 次,因為這兩個指令都是都是內建指令,因此他們的 Total Time 會等於 Self Time,所花的時間都可以由上表一目瞭然。
若要知道 mean 函式的內部計時情況,可以點選上述視窗的 “mean” 連結,結果如下:
由上圖可以得到 mean 函式的內部計時結果,我們甚至可以看到最花時間的敘述出現在第 28 列,根據這些訊息,我們就可以使用「擒賊擒王」的原則來對此列進行最佳化,以求整體計算速度的提昇。在上圖列表,亦包含了所有內建指令的計時資料。此時若再點選任一個函式連結,就可以更清楚地看出每一個指令的 parent 指令(即呼叫此指令的上層指令)和 children 指令(即被此指令所呼叫的下層指令),以及他們各自所佔用的時間。
在上述範例中,MATLAB 計時器在預設的情況下,是對所有的函式進行計時,這些函式包含 M 檔案、MEX 檔案,以及內建指令。但通常內建指令已經是最佳化的狀態,通常不太可能去加速,我們可以改變計時器,只針對 M 檔案及 MEX 檔案進行計時,因為這兩種檔案才比較有改善的空間。欲使 profile 指令只對 M 檔案及 MEX 檔案進行計時,可在 profile on 之後接上「-detail mmex」,例如:
此時計時結果將只有包含 M 檔案及 MEX 檔案,如下圖:
由於我們只在意 M 檔案(這裡只有 mean 指令)和 MEX 檔案(在這裡並未出現)的執行時間,所以整個報表變得相當簡單。我們仍然可以點選上述視窗的 “mean” 連結,就可以看到此函式內部執行所花的時間。